Library Environment

suppressMessages(library(tidyverse))
suppressMessages(library(stringr))
#suppressMessages(library(ISLR))
suppressMessages(library(caret))
suppressMessages(library(doMC))
#suppressMessages(library(plotly))
#suppressMessages(library(stringr))
registerDoMC(cores=4)

Load and processing data ctu13 cleaned

feature_vectors_cleaned
            sp         wp        wnp         snp          ds          dm         dl         ss
1  0.023980324 0.02910432 0.12174626 0.324861652 0.441483911 0.046320967 0.01229760 0.32035253
2  0.480492813 0.01642710 0.00000000 0.000000000 0.490759754 0.010266940 0.00000000 0.00000000
3  0.384615385 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
4  0.000000000 0.01886792 0.18867925 0.264150943 0.000000000 0.037735849 0.47169811 0.00000000
5  0.000000000 0.00000000 0.31250000 0.062500000 0.000000000 0.000000000 0.50000000 0.00000000
6  0.307692308 0.00000000 0.07692308 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
7  0.009990838 0.02277388 0.07490947 0.392260373 0.438026264 0.028532787 0.03346276 0.16042058
8  0.054333765 0.04786546 0.29495472 0.100905563 0.477360931 0.000000000 0.02328590 0.00000000
9  0.497124076 0.00000000 0.00000000 0.001643385 0.000000000 0.500410846 0.00000000 0.00000000
10 0.384615385 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
11 0.041198502 0.02496879 0.29588015 0.136079900 0.459425718 0.013732834 0.02746567 0.00000000
12 0.384615385 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
13 0.000000000 0.09523810 0.23809524 0.095238095 0.000000000 0.000000000 0.52380952 0.00000000
14 0.384615385 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
15 0.384615385 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
16 0.000000000 0.00000000 0.00000000 0.307692308 0.000000000 0.000000000 0.46153846 0.00000000
17 0.036755387 0.04562738 0.29531052 0.120405577 0.470215463 0.000000000 0.03041825 0.00000000
18 0.200000000 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.60000000 0.00000000
19 0.277372263 0.01459854 0.13868613 0.058394161 0.394160584 0.000000000 0.10948905 0.39416058
20 0.254901961 0.00000000 0.17647059 0.039215686 0.000000000 0.509803922 0.00000000 0.00000000
21 0.301886792 0.00000000 0.16981132 0.000000000 0.000000000 0.509433962 0.00000000 0.00000000
22 0.320754717 0.00000000 0.15094340 0.000000000 0.000000000 0.509433962 0.00000000 0.00000000
23 0.030769231 0.03216783 0.30909091 0.125874126 0.488111888 0.000000000 0.01258741 0.00000000
24 0.002197802 0.03296703 0.09890110 0.362637363 0.501098901 0.000000000 0.00000000 0.42417582
25 0.307692308 0.00000000 0.07692308 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
26 0.030476190 0.08380952 0.05904762 0.323809524 0.007619048 0.415238095 0.07809524 0.00000000
27 0.039783002 0.04882459 0.09222423 0.316455696 0.007233273 0.408679928 0.08499096 0.00000000
28 0.307692308 0.00000000 0.07692308 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
29 0.043586550 0.03237858 0.30510585 0.117061021 0.481942715 0.000000000 0.01867995 0.00000000
30 0.000000000 0.02985075 0.32835821 0.119402985 0.000000000 0.000000000 0.50746269 0.00000000
31 0.028985507 0.07246377 0.23188406 0.144927536 0.000000000 0.000000000 0.50724638 0.00000000
32 0.040404040 0.04617605 0.28571429 0.125541126 0.470418470 0.002886003 0.02741703 0.00000000
33 0.076923077 0.00000000 0.30769231 0.000000000 0.000000000 0.000000000 0.53846154 0.00000000
34 0.181818182 0.18181818 0.00000000 0.000000000 0.000000000 0.000000000 0.54545455 0.00000000
35 0.012606169 0.03719267 0.11569066 0.334376397 0.451497541 0.033616451 0.01493071 0.31282968
36 0.000000000 0.23076923 0.07692308 0.076923077 0.000000000 0.000000000 0.53846154 0.00000000
37 0.012987013 0.05194805 0.22077922 0.194805195 0.000000000 0.000000000 0.50649351 0.00000000
38 0.363636364 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.54545455 0.00000000
39 0.000000000 0.09836066 0.13114754 0.229508197 0.000000000 0.049180328 0.44262295 0.00000000
40 0.000000000 0.00000000 0.01666667 0.450000000 0.000000000 0.000000000 0.50000000 0.00000000
41 0.043478261 0.04347826 0.00000000 0.304347826 0.000000000 0.130434783 0.34782609 0.00000000
42 0.311475410 0.00000000 0.16393443 0.000000000 0.000000000 0.508196721 0.00000000 0.00000000
43 0.071428571 0.00000000 0.07142857 0.214285714 0.000000000 0.071428571 0.42857143 0.00000000
44 0.363636364 0.00000000 0.00000000 0.000000000 0.090909091 0.000000000 0.45454545 0.09090909
45 0.066666667 0.00000000 0.00000000 0.266666667 0.000000000 0.133333333 0.33333333 0.00000000
46 0.000000000 0.00000000 0.00000000 0.250000000 0.125000000 0.250000000 0.12500000 0.00000000
47 0.041666667 0.04166667 0.08333333 0.250000000 0.000000000 0.000000000 0.50000000 0.00000000
48 0.000000000 0.02941176 0.11764706 0.294117647 0.264705882 0.235294118 0.00000000 0.00000000
49 0.000000000 0.04166667 0.08333333 0.291666667 0.000000000 0.000000000 0.50000000 0.00000000
50 0.000000000 0.00000000 0.00000000 0.250000000 0.000000000 0.000000000 0.50000000 0.00000000
51 0.000000000 0.07692308 0.07692308 0.269230769 0.000000000 0.076923077 0.42307692 0.00000000
52 0.000000000 0.00000000 0.00000000 0.300000000 0.000000000 0.000000000 0.50000000 0.00000000
53 0.000000000 0.00000000 0.00000000 0.250000000 0.250000000 0.250000000 0.00000000 0.00000000
54 0.000000000 0.00000000 0.04166667 0.375000000 0.291666667 0.083333333 0.12500000 0.00000000
55 0.000000000 0.00000000 0.00000000 0.357142857 0.500000000 0.000000000 0.00000000 0.00000000
56 0.000000000 0.00000000 0.09375000 0.343750000 0.000000000 0.062500000 0.43750000 0.00000000
57 0.000000000 0.00000000 0.00000000 0.375000000 0.000000000 0.000000000 0.50000000 0.00000000
58 0.009523810 0.07619048 0.07619048 0.323809524 0.000000000 0.000000000 0.50476190 0.00000000
59 0.000000000 0.00000000 0.00000000 0.300000000 0.200000000 0.100000000 0.20000000 0.00000000
60 0.000000000 0.00000000 0.00000000 0.250000000 0.000000000 0.250000000 0.25000000 0.00000000
61 0.000000000 0.05555556 0.05555556 0.277777778 0.000000000 0.000000000 0.50000000 0.00000000
62 0.000000000 0.00000000 0.18518519 0.277777778 0.000000000 0.000000000 0.50000000 0.00000000
63 0.000000000 0.00000000 0.06250000 0.250000000 0.000000000 0.000000000 0.43750000 0.00000000
64 0.000000000 0.08571429 0.17142857 0.200000000 0.171428571 0.200000000 0.14285714 0.00000000
65 0.000000000 0.20000000 0.00000000 0.000000000 0.000000000 0.000000000 0.60000000 0.00000000
66 0.000000000 0.14285714 0.00000000 0.000000000 0.000000000 0.000000000 0.42857143 0.00000000
           sm           sl modelsize                          class subclass port proto
1  0.17954499 2.049600e-04      4879                 Normal-UDP-DNS   normal   53   udp
2  0.00000000 5.010267e-01       487                Normal-TCP-HTTP   normal   80   tcp
3  0.00000000 5.384615e-01        13                Normal-TCP-HTTP   normal  443   tcp
4  0.13207547 3.773585e-01        53                Normal-TCP-HTTP   normal   80   tcp
5  0.06250000 4.375000e-01        16                Normal-TCP-HTTP   normal   80   tcp
6  0.15384615 3.846154e-01        13          Normal-UDP-NTP-server   normal  123   udp
7  0.33933947 2.617687e-04     22921                 Normal-UDP-DNS   normal   53   udp
8  0.49547219 5.174644e-03       773                Normal-TCP-HTTP   normal   80   tcp
9  0.00000000 5.004108e-01      1217                Normal-TCP-HTTP   normal   80   tcp
10 0.07692308 4.615385e-01        13              Normal-TCP-Jabber   normal 5222   tcp
11 0.47815231 2.247191e-02       801                Normal-TCP-HTTP   normal   80   tcp
12 0.00000000 5.384615e-01        13              Normal-TCP-Jabber   normal 5222   tcp
13 0.04761905 4.761905e-01        21                Normal-TCP-HTTP   normal  443   tcp
14 0.07692308 4.615385e-01        13                Normal-TCP-HTTP   normal  443   tcp
15 0.00000000 5.384615e-01        13                Normal-TCP-HTTP   normal  443   tcp
16 0.30769231 1.538462e-01        13                Normal-TCP-HTTP   normal   80   tcp
17 0.49176172 8.871990e-03       789                Normal-TCP-HTTP   normal   80   tcp
18 0.20000000 4.000000e-01         5                 Normal-TCP-MSN   normal 1863   tcp
19 0.04379562 6.569343e-02       137          Normal-UDP-NTP-server   normal  123   udp
20 0.00000000 5.098039e-01        51                Normal-TCP-HTTP   normal  443   tcp
21 0.00000000 5.094340e-01        53                Normal-TCP-HTTP   normal  443   tcp
22 0.00000000 5.094340e-01        53                Normal-TCP-HTTP   normal  443   tcp
23 0.49790210 2.797203e-03       715                Normal-TCP-HTTP   normal   80   tcp
24 0.07692308 0.000000e+00       455 Normal-TCP-HTTP-CVUT-WebServer   normal   53   udp
25 0.07692308 4.615385e-01        13          Normal-UDP-NTP-server   normal  123   udp
26 0.00000000 5.009524e-01       525                Normal-TCP-HTTP   normal  443   tcp
27 0.00000000 5.009042e-01       553                Normal-TCP-HTTP   normal  443   tcp
28 0.07692308 4.615385e-01        13          Normal-UDP-NTP-server   normal  123   udp
29 0.49439601 6.226650e-03       803                Normal-TCP-HTTP   normal   80   tcp
30 0.00000000 5.074627e-01        67                Normal-TCP-HTTP   normal  443   tcp
31 0.00000000 5.072464e-01        69                Normal-TCP-HTTP   normal  443   tcp
32 0.48629149 1.443001e-02       693                Normal-TCP-HTTP   normal   80   tcp
33 0.07692308 4.615385e-01        13          Normal-UDP-NTP-server   normal  123   udp
34 0.00000000 5.454545e-01        11          Normal-UDP-NTP-server   normal  123   udp
35 0.18712561 8.940545e-05     11185                 Normal-UDP-DNS   normal   53   udp
36 0.00000000 5.384615e-01        13                Normal-TCP-IMAP   normal  993   tcp
37 0.00000000 5.064935e-01        77                Normal-TCP-HTTP   normal  443   tcp
38 0.54545455 0.000000e+00        11          Normal-UDP-NTP-server   normal  123   udp
39 0.36065574 1.311475e-01        61                Normal-TCP-HTTP   normal   80   tcp
40 0.46666667 3.333333e-02        60                Normal-TCP-HTTP   normal   80   tcp
41 0.17391304 3.043478e-01        23                Normal-TCP-HTTP   normal   80   tcp
42 0.00000000 5.081967e-01        61                Normal-TCP-HTTP   normal  443   tcp
43 0.00000000 5.000000e-01        14                Normal-TCP-HTTP   normal  443   tcp
44 0.45454545 0.000000e+00        11          Normal-UDP-NTP-server   normal  123   udp
45 0.00000000 4.666667e-01        15                Normal-TCP-HTTP   normal   80   tcp
46 0.12500000 3.750000e-01         8                Normal-TCP-HTTP   normal   80   tcp
47 0.00000000 5.000000e-01        24                Normal-TCP-HTTP   normal   80   tcp
48 0.17647059 3.235294e-01        34                Normal-TCP-HTTP   normal   80   tcp
49 0.20833333 2.916667e-01        24                Normal-TCP-HTTP   normal   80   tcp
50 0.25000000 2.500000e-01         8                Normal-TCP-HTTP   normal   80   tcp
51 0.03846154 4.615385e-01        26                Normal-TCP-HTTP   normal   80   tcp
52 0.30000000 2.000000e-01        10                Normal-TCP-HTTP   normal   80   tcp
53 0.12500000 3.750000e-01         8                Normal-TCP-HTTP   normal   80   tcp
54 0.12500000 3.750000e-01        24                Normal-TCP-HTTP   normal   80   tcp
55 0.00000000 5.000000e-01        14                Normal-TCP-HTTP   normal   80   tcp
56 0.12500000 3.750000e-01        32                Normal-TCP-HTTP   normal   80   tcp
57 0.12500000 3.750000e-01        16                Normal-TCP-HTTP   normal   80   tcp
58 0.07619048 4.285714e-01       105                Normal-TCP-HTTP   normal   80   tcp
59 0.20000000 3.000000e-01        10                Normal-TCP-HTTP   normal   80   tcp
60 0.25000000 2.500000e-01         8                Normal-TCP-HTTP   normal   80   tcp
61 0.11111111 3.888889e-01        18                Normal-TCP-HTTP   normal   80   tcp
62 0.29629630 2.037037e-01        54                Normal-TCP-HTTP   normal   80   tcp
63 0.18750000 2.500000e-01        16                Normal-TCP-HTTP   normal   80   tcp
64 0.14285714 3.714286e-01        35                Normal-TCP-HTTP   normal   80   tcp
65 0.00000000 6.000000e-01         5                Normal-TCP-HTTP   normal   80   tcp
66 0.00000000 4.285714e-01         7                Normal-TCP-HTTP   normal   80   tcp
 [ reached 'max' / getOption("max.print") -- omitted 8922 rows ]

Removing excesive Botnet and Normal class(Making the dataset more equitable)

feature_vectors_cleaned.bkp <- feature_vectors_cleaned
feature_vectors_cleaned %>% group_by(class) %>% summarise(n=n()) %>% arrange(desc(n))
# A tibble: 47 x 2
   class                                      n
   <fct>                                  <int>
 1 Botnet-TCP-SMTP-Attempt-SPAM            4297
 2 Normal-TCP-HTTP                         2602
 3 Botnet-TCP-HTTP-Established-Ad           487
 4 Botnet-TCP-HTTP-Established              377
 5 Botnet-UDP-DNS                           301
 6 Botnet-TCP-HTTP-Established-SSL          210
 7 Botnet-TCP-HTTP-CC-Not-Encrypted          68
 8 Normal-UDP-NTP-server                     67
 9 Botnet-TCP-HTTPS-Established-Microsoft    58
10 Botnet-TCP-HTTP-Google-Net-Established    50
# ... with 37 more rows
feature_vectors_cleaned_aux_botnet <- feature_vectors_cleaned %>% filter(class == 'Botnet-TCP-SMTP-Attempt-SPAM')
feature_vectors_cleaned_aux_normal <- feature_vectors_cleaned %>% filter(class == 'Normal-TCP-HTTP')
feature_vectors_cleaned_aux_botnet
            sp         wp        wnp        snp          ds        dm          dl        ss
1  0.097560976 0.14634146 0.21951220 0.00000000 0.000000000 0.5121951 0.000000000 0.0000000
2  0.000000000 0.00000000 0.20000000 0.00000000 0.000000000 0.6000000 0.000000000 0.6000000
3  0.074074074 0.03703704 0.33333333 0.00000000 0.000000000 0.5185185 0.000000000 0.5185185
4  0.000000000 0.00000000 0.00000000 0.20000000 0.200000000 0.4000000 0.000000000 0.2000000
5  0.000000000 0.03597122 0.28057554 0.17266187 0.000000000 0.4964029 0.007194245 0.5035971
6  0.000000000 0.00000000 0.16666667 0.16666667 0.000000000 0.5000000 0.000000000 0.0000000
7  0.000000000 0.00000000 0.20000000 0.00000000 0.000000000 0.6000000 0.000000000 0.6000000
8  0.000000000 0.00000000 0.20000000 0.00000000 0.200000000 0.4000000 0.000000000 0.6000000
9  0.000000000 0.00000000 0.16666667 0.00000000 0.000000000 0.5000000 0.000000000 0.5000000
10 0.000000000 0.00000000 0.28571429 0.00000000 0.000000000 0.5714286 0.000000000 0.5714286
11 0.000000000 0.00000000 0.00000000 0.20000000 0.000000000 0.6000000 0.000000000 0.4000000
12 0.000000000 0.00000000 0.20000000 0.00000000 0.000000000 0.6000000 0.000000000 0.0000000
13 0.000000000 0.00000000 0.00000000 0.14285714 0.142857143 0.2857143 0.000000000 0.4285714
14 0.000000000 0.00000000 0.00000000 0.20000000 0.000000000 0.6000000 0.000000000 0.6000000
15 0.000000000 0.00000000 0.00000000 0.14285714 0.000000000 0.4285714 0.000000000 0.4285714
16 0.000000000 0.20000000 0.00000000 0.00000000 0.000000000 0.6000000 0.000000000 0.0000000
17 0.000000000 0.00000000 0.16666667 0.00000000 0.000000000 0.5000000 0.000000000 0.5000000
18 0.000000000 0.00000000 0.00000000 0.00000000 0.000000000 0.4000000 0.000000000 0.4000000
19 0.006960557 0.08352668 0.26914153 0.13689095 0.000000000 0.4988399 0.002320186 0.5011601
20 0.000000000 0.00000000 0.20000000 0.00000000 0.000000000 0.6000000 0.000000000 0.6000000
21 0.000000000 0.00000000 0.20000000 0.00000000 0.200000000 0.4000000 0.000000000 0.6000000
22 0.000000000 0.00000000 0.00000000 0.00000000 0.000000000 0.4000000 0.000000000 0.4000000
23 0.000000000 0.00000000 0.00000000 0.14285714 0.000000000 0.4285714 0.000000000 0.4285714
24 0.000000000 0.00000000 0.14285714 0.14285714 0.142857143 0.4285714 0.000000000 0.5714286
25 0.007407407 0.04444444 0.27407407 0.16296296 0.022222222 0.4814815 0.000000000 0.5037037
26 0.015267176 0.03816794 0.30534351 0.12977099 0.022900763 0.4809160 0.000000000 0.5038168
27 0.000000000 0.02127660 0.29787234 0.14893617 0.000000000 0.5106383 0.000000000 0.5106383
28 0.012875536 0.03433476 0.29184549 0.15450644 0.004291845 0.4978541 0.000000000 0.5021459
29 0.025641026 0.11111111 0.29344729 0.06552707 0.000000000 0.5014245 0.000000000 0.5014245
30 0.000000000 0.05882353 0.00000000 0.29411765 0.000000000 0.4705882 0.000000000 0.4705882
31 0.016806723 0.05882353 0.20168067 0.21008403 0.000000000 0.5042017 0.000000000 0.5042017
32 0.026785714 0.03571429 0.21428571 0.20535714 0.008928571 0.4821429 0.008928571 0.5000000
33 0.012658228 0.05063291 0.21518987 0.20253165 0.012658228 0.4936709 0.000000000 0.5063291
34 0.000000000 0.11111111 0.00000000 0.22222222 0.111111111 0.4444444 0.000000000 0.1111111
35 0.005494505 0.08791209 0.30769231 0.08791209 0.005494505 0.4945055 0.000000000 0.5000000
36 0.000000000 0.03278689 0.34426230 0.09836066 0.000000000 0.5081967 0.000000000 0.5081967
37 0.000000000 0.00000000 0.00000000 0.20000000 0.200000000 0.4000000 0.000000000 0.6000000
38 0.000000000 0.15384615 0.07692308 0.15384615 0.076923077 0.4615385 0.000000000 0.5384615
39 0.008695652 0.03478261 0.29565217 0.14782609 0.008695652 0.4956522 0.000000000 0.5043478
40 0.000000000 0.03773585 0.22641509 0.20754717 0.000000000 0.5094340 0.000000000 0.5094340
41 0.000000000 0.00000000 0.27272727 0.09090909 0.090909091 0.4545455 0.000000000 0.5454545
42 0.005586592 0.07262570 0.20111732 0.21229050 0.005586592 0.4972067 0.000000000 0.5027933
43 0.000000000 0.00000000 0.00000000 0.20000000 0.000000000 0.6000000 0.000000000 0.6000000
44 0.000000000 0.01886792 0.20754717 0.24528302 0.000000000 0.5094340 0.000000000 0.5094340
45 0.000000000 0.00000000 0.20000000 0.00000000 0.000000000 0.6000000 0.000000000 0.6000000
46 0.000000000 0.00000000 0.14285714 0.14285714 0.285714286 0.2857143 0.000000000 0.5714286
47 0.032786885 0.06557377 0.24590164 0.13114754 0.000000000 0.5081967 0.000000000 0.5081967
48 0.000000000 0.00000000 0.20000000 0.10000000 0.100000000 0.4000000 0.000000000 0.5000000
49 0.000000000 0.00000000 0.07407407 0.37037037 0.037037037 0.4814815 0.000000000 0.5185185
50 0.100000000 0.00000000 0.20000000 0.00000000 0.000000000 0.5000000 0.000000000 0.5000000
51 0.015384615 0.04615385 0.26153846 0.15384615 0.015384615 0.4923077 0.000000000 0.5076923
52 0.000000000 0.00000000 0.00000000 0.28571429 0.000000000 0.5714286 0.000000000 0.5714286
53 0.000000000 0.14285714 0.14285714 0.00000000 0.000000000 0.5714286 0.000000000 0.5714286
54 0.047619048 0.00000000 0.28571429 0.09523810 0.000000000 0.5238095 0.000000000 0.5238095
55 0.013698630 0.02739726 0.16438356 0.27397260 0.000000000 0.5068493 0.000000000 0.5068493
56 0.000000000 0.00000000 0.16666667 0.00000000 0.000000000 0.5000000 0.000000000 0.5000000
57 0.000000000 0.03508772 0.21052632 0.22807018 0.000000000 0.5087719 0.000000000 0.5087719
58 0.142857143 0.00000000 0.14285714 0.00000000 0.000000000 0.5714286 0.000000000 0.5714286
59 0.034168565 0.06833713 0.24601367 0.14806378 0.000000000 0.5011390 0.000000000 0.5011390
60 0.015873016 0.07936508 0.28571429 0.09523810 0.000000000 0.5079365 0.000000000 0.5079365
61 0.023255814 0.00000000 0.23255814 0.20930233 0.000000000 0.5116279 0.000000000 0.5116279
62 0.000000000 0.00000000 0.00000000 0.28571429 0.000000000 0.5714286 0.000000000 0.5714286
63 0.025641026 0.02564103 0.23076923 0.17948718 0.000000000 0.5128205 0.000000000 0.5128205
64 0.000000000 0.00000000 0.00000000 0.16666667 0.000000000 0.5000000 0.000000000 0.5000000
65 0.000000000 0.00000000 0.00000000 0.00000000 0.000000000 0.4000000 0.000000000 0.4000000
66 0.000000000 0.14285714 0.14285714 0.00000000 0.000000000 0.5714286 0.000000000 0.5714286
          sm sl modelsize                        class subclass port proto
1  0.5121951  0        41 Botnet-TCP-SMTP-Attempt-SPAM   botnet  443   tcp
2  0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
3  0.0000000  0        27 Botnet-TCP-SMTP-Attempt-SPAM   botnet  443   tcp
4  0.4000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
5  0.0000000  0       139 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
6  0.5000000  0        12 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
7  0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
8  0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
9  0.0000000  0         6 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
10 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
11 0.2000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
12 0.6000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
13 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
14 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
15 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
16 0.6000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
17 0.0000000  0         6 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
18 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
19 0.0000000  0       431 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
20 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
21 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
22 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
23 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
24 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
25 0.0000000  0       135 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
26 0.0000000  0       131 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
27 0.0000000  0        47 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
28 0.0000000  0       233 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
29 0.0000000  0       351 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
30 0.0000000  0        17 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
31 0.0000000  0       119 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
32 0.0000000  0       112 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
33 0.0000000  0        79 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
34 0.4444444  0         9 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
35 0.0000000  0       182 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
36 0.0000000  0        61 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
37 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
38 0.0000000  0        13 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
39 0.0000000  0       115 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
40 0.0000000  0        53 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
41 0.0000000  0        11 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
42 0.0000000  0       179 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
43 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
44 0.0000000  0        53 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
45 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
46 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
47 0.0000000  0        61 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
48 0.0000000  0        10 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
49 0.0000000  0        27 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
50 0.0000000  0        10 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
51 0.0000000  0        65 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
52 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
53 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
54 0.0000000  0        21 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
55 0.0000000  0        73 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
56 0.0000000  0         6 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
57 0.0000000  0        57 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
58 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
59 0.0000000  0       439 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
60 0.0000000  0        63 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
61 0.0000000  0        43 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
62 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
63 0.0000000  0        39 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
64 0.0000000  0         6 Botnet-TCP-SMTP-Attempt-SPAM   botnet   25   tcp
65 0.0000000  0         5 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
66 0.0000000  0         7 Botnet-TCP-SMTP-Attempt-SPAM   botnet 6667   tcp
 [ reached 'max' / getOption("max.print") -- omitted 4231 rows ]
feature_vectors_cleaned_aux_normal
           sp         wp        wnp         snp          ds          dm          dl ss
1  0.48049281 0.01642710 0.00000000 0.000000000 0.490759754 0.010266940 0.000000000  0
2  0.38461538 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.538461538  0
3  0.00000000 0.01886792 0.18867925 0.264150943 0.000000000 0.037735849 0.471698113  0
4  0.00000000 0.00000000 0.31250000 0.062500000 0.000000000 0.000000000 0.500000000  0
5  0.05433376 0.04786546 0.29495472 0.100905563 0.477360931 0.000000000 0.023285899  0
6  0.49712408 0.00000000 0.00000000 0.001643385 0.000000000 0.500410846 0.000000000  0
7  0.04119850 0.02496879 0.29588015 0.136079900 0.459425718 0.013732834 0.027465668  0
8  0.00000000 0.09523810 0.23809524 0.095238095 0.000000000 0.000000000 0.523809524  0
9  0.38461538 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.538461538  0
10 0.38461538 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.538461538  0
11 0.00000000 0.00000000 0.00000000 0.307692308 0.000000000 0.000000000 0.461538462  0
12 0.03675539 0.04562738 0.29531052 0.120405577 0.470215463 0.000000000 0.030418251  0
13 0.25490196 0.00000000 0.17647059 0.039215686 0.000000000 0.509803922 0.000000000  0
14 0.30188679 0.00000000 0.16981132 0.000000000 0.000000000 0.509433962 0.000000000  0
15 0.32075472 0.00000000 0.15094340 0.000000000 0.000000000 0.509433962 0.000000000  0
16 0.03076923 0.03216783 0.30909091 0.125874126 0.488111888 0.000000000 0.012587413  0
17 0.03047619 0.08380952 0.05904762 0.323809524 0.007619048 0.415238095 0.078095238  0
18 0.03978300 0.04882459 0.09222423 0.316455696 0.007233273 0.408679928 0.084990958  0
19 0.04358655 0.03237858 0.30510585 0.117061021 0.481942715 0.000000000 0.018679950  0
20 0.00000000 0.02985075 0.32835821 0.119402985 0.000000000 0.000000000 0.507462687  0
21 0.02898551 0.07246377 0.23188406 0.144927536 0.000000000 0.000000000 0.507246377  0
22 0.04040404 0.04617605 0.28571429 0.125541126 0.470418470 0.002886003 0.027417027  0
23 0.01298701 0.05194805 0.22077922 0.194805195 0.000000000 0.000000000 0.506493506  0
24 0.00000000 0.09836066 0.13114754 0.229508197 0.000000000 0.049180328 0.442622951  0
25 0.00000000 0.00000000 0.01666667 0.450000000 0.000000000 0.000000000 0.500000000  0
26 0.04347826 0.04347826 0.00000000 0.304347826 0.000000000 0.130434783 0.347826087  0
27 0.31147541 0.00000000 0.16393443 0.000000000 0.000000000 0.508196721 0.000000000  0
28 0.07142857 0.00000000 0.07142857 0.214285714 0.000000000 0.071428571 0.428571429  0
29 0.06666667 0.00000000 0.00000000 0.266666667 0.000000000 0.133333333 0.333333333  0
30 0.00000000 0.00000000 0.00000000 0.250000000 0.125000000 0.250000000 0.125000000  0
31 0.04166667 0.04166667 0.08333333 0.250000000 0.000000000 0.000000000 0.500000000  0
32 0.00000000 0.02941176 0.11764706 0.294117647 0.264705882 0.235294118 0.000000000  0
33 0.00000000 0.04166667 0.08333333 0.291666667 0.000000000 0.000000000 0.500000000  0
34 0.00000000 0.00000000 0.00000000 0.250000000 0.000000000 0.000000000 0.500000000  0
35 0.00000000 0.07692308 0.07692308 0.269230769 0.000000000 0.076923077 0.423076923  0
36 0.00000000 0.00000000 0.00000000 0.300000000 0.000000000 0.000000000 0.500000000  0
37 0.00000000 0.00000000 0.00000000 0.250000000 0.250000000 0.250000000 0.000000000  0
38 0.00000000 0.00000000 0.04166667 0.375000000 0.291666667 0.083333333 0.125000000  0
39 0.00000000 0.00000000 0.00000000 0.357142857 0.500000000 0.000000000 0.000000000  0
40 0.00000000 0.00000000 0.09375000 0.343750000 0.000000000 0.062500000 0.437500000  0
41 0.00000000 0.00000000 0.00000000 0.375000000 0.000000000 0.000000000 0.500000000  0
42 0.00952381 0.07619048 0.07619048 0.323809524 0.000000000 0.000000000 0.504761905  0
43 0.00000000 0.00000000 0.00000000 0.300000000 0.200000000 0.100000000 0.200000000  0
44 0.00000000 0.00000000 0.00000000 0.250000000 0.000000000 0.250000000 0.250000000  0
45 0.00000000 0.05555556 0.05555556 0.277777778 0.000000000 0.000000000 0.500000000  0
46 0.00000000 0.00000000 0.18518519 0.277777778 0.000000000 0.000000000 0.500000000  0
47 0.00000000 0.00000000 0.06250000 0.250000000 0.000000000 0.000000000 0.437500000  0
48 0.00000000 0.08571429 0.17142857 0.200000000 0.171428571 0.200000000 0.142857143  0
49 0.00000000 0.20000000 0.00000000 0.000000000 0.000000000 0.000000000 0.600000000  0
50 0.00000000 0.14285714 0.00000000 0.000000000 0.000000000 0.000000000 0.428571429  0
51 0.00000000 0.00000000 0.00000000 0.409090909 0.363636364 0.045454545 0.090909091  0
52 0.01935484 0.03225806 0.07096774 0.367741935 0.000000000 0.000000000 0.503225806  0
53 0.00000000 0.00000000 0.20833333 0.208333333 0.041666667 0.083333333 0.375000000  0
54 0.03333333 0.03333333 0.10000000 0.233333333 0.000000000 0.233333333 0.233333333  0
55 0.05263158 0.05263158 0.10526316 0.210526316 0.000000000 0.000000000 0.526315789  0
56 0.00000000 0.02564103 0.10256410 0.307692308 0.000000000 0.051282051 0.435897436  0
57 0.09523810 0.04761905 0.00000000 0.190476190 0.000000000 0.142857143 0.285714286  0
58 0.00000000 0.00000000 0.00000000 0.111111111 0.000000000 0.000000000 0.333333333  0
59 0.00000000 0.00000000 0.00000000 0.181818182 0.000000000 0.000000000 0.363636364  0
60 0.00000000 0.00000000 0.00000000 0.000000000 0.000000000 0.000000000 0.285714286  0
61 0.00000000 0.00000000 0.00000000 0.285714286 0.000000000 0.000000000 0.571428571  0
62 0.01538462 0.03076923 0.35384615 0.076923077 0.000000000 0.000000000 0.507692308  0
63 0.01694915 0.06779661 0.06779661 0.322033898 0.000000000 0.016949153 0.491525424  0
64 0.06666667 0.20000000 0.18974359 0.035897436 0.000000000 0.005128205 0.497435897  0
65 0.01023018 0.01790281 0.02557545 0.442455243 0.002557545 0.496163683 0.002557545  0
66 0.00000000 0.04255319 0.08510638 0.340425532 0.021276596 0.000000000 0.489361702  0
            sm          sl modelsize           class subclass port proto
1  0.000000000 0.501026694       487 Normal-TCP-HTTP   normal   80   tcp
2  0.000000000 0.538461538        13 Normal-TCP-HTTP   normal  443   tcp
3  0.132075472 0.377358491        53 Normal-TCP-HTTP   normal   80   tcp
4  0.062500000 0.437500000        16 Normal-TCP-HTTP   normal   80   tcp
5  0.495472186 0.005174644       773 Normal-TCP-HTTP   normal   80   tcp
6  0.000000000 0.500410846      1217 Normal-TCP-HTTP   normal   80   tcp
7  0.478152310 0.022471910       801 Normal-TCP-HTTP   normal   80   tcp
8  0.047619048 0.476190476        21 Normal-TCP-HTTP   normal  443   tcp
9  0.076923077 0.461538462        13 Normal-TCP-HTTP   normal  443   tcp
10 0.000000000 0.538461538        13 Normal-TCP-HTTP   normal  443   tcp
11 0.307692308 0.153846154        13 Normal-TCP-HTTP   normal   80   tcp
12 0.491761724 0.008871990       789 Normal-TCP-HTTP   normal   80   tcp
13 0.000000000 0.509803922        51 Normal-TCP-HTTP   normal  443   tcp
14 0.000000000 0.509433962        53 Normal-TCP-HTTP   normal  443   tcp
15 0.000000000 0.509433962        53 Normal-TCP-HTTP   normal  443   tcp
16 0.497902098 0.002797203       715 Normal-TCP-HTTP   normal   80   tcp
17 0.000000000 0.500952381       525 Normal-TCP-HTTP   normal  443   tcp
18 0.000000000 0.500904159       553 Normal-TCP-HTTP   normal  443   tcp
19 0.494396015 0.006226650       803 Normal-TCP-HTTP   normal   80   tcp
20 0.000000000 0.507462687        67 Normal-TCP-HTTP   normal  443   tcp
21 0.000000000 0.507246377        69 Normal-TCP-HTTP   normal  443   tcp
22 0.486291486 0.014430014       693 Normal-TCP-HTTP   normal   80   tcp
23 0.000000000 0.506493506        77 Normal-TCP-HTTP   normal  443   tcp
24 0.360655738 0.131147541        61 Normal-TCP-HTTP   normal   80   tcp
25 0.466666667 0.033333333        60 Normal-TCP-HTTP   normal   80   tcp
26 0.173913043 0.304347826        23 Normal-TCP-HTTP   normal   80   tcp
27 0.000000000 0.508196721        61 Normal-TCP-HTTP   normal  443   tcp
28 0.000000000 0.500000000        14 Normal-TCP-HTTP   normal  443   tcp
29 0.000000000 0.466666667        15 Normal-TCP-HTTP   normal   80   tcp
30 0.125000000 0.375000000         8 Normal-TCP-HTTP   normal   80   tcp
31 0.000000000 0.500000000        24 Normal-TCP-HTTP   normal   80   tcp
32 0.176470588 0.323529412        34 Normal-TCP-HTTP   normal   80   tcp
33 0.208333333 0.291666667        24 Normal-TCP-HTTP   normal   80   tcp
34 0.250000000 0.250000000         8 Normal-TCP-HTTP   normal   80   tcp
35 0.038461538 0.461538462        26 Normal-TCP-HTTP   normal   80   tcp
36 0.300000000 0.200000000        10 Normal-TCP-HTTP   normal   80   tcp
37 0.125000000 0.375000000         8 Normal-TCP-HTTP   normal   80   tcp
38 0.125000000 0.375000000        24 Normal-TCP-HTTP   normal   80   tcp
39 0.000000000 0.500000000        14 Normal-TCP-HTTP   normal   80   tcp
40 0.125000000 0.375000000        32 Normal-TCP-HTTP   normal   80   tcp
41 0.125000000 0.375000000        16 Normal-TCP-HTTP   normal   80   tcp
42 0.076190476 0.428571429       105 Normal-TCP-HTTP   normal   80   tcp
43 0.200000000 0.300000000        10 Normal-TCP-HTTP   normal   80   tcp
44 0.250000000 0.250000000         8 Normal-TCP-HTTP   normal   80   tcp
45 0.111111111 0.388888889        18 Normal-TCP-HTTP   normal   80   tcp
46 0.296296296 0.203703704        54 Normal-TCP-HTTP   normal   80   tcp
47 0.187500000 0.250000000        16 Normal-TCP-HTTP   normal   80   tcp
48 0.142857143 0.371428571        35 Normal-TCP-HTTP   normal   80   tcp
49 0.000000000 0.600000000         5 Normal-TCP-HTTP   normal   80   tcp
50 0.000000000 0.428571429         7 Normal-TCP-HTTP   normal   80   tcp
51 0.090909091 0.409090909        22 Normal-TCP-HTTP   normal   80   tcp
52 0.070967742 0.432258065       155 Normal-TCP-HTTP   normal   80   tcp
53 0.000000000 0.500000000        24 Normal-TCP-HTTP   normal   80   tcp
54 0.133333333 0.333333333        30 Normal-TCP-HTTP   normal   80   tcp
55 0.000000000 0.526315789        19 Normal-TCP-HTTP   normal   80   tcp
56 0.333333333 0.153846154        39 Normal-TCP-HTTP   normal   80   tcp
57 0.000000000 0.428571429        21 Normal-TCP-HTTP   normal   80   tcp
58 0.000000000 0.333333333         9 Normal-TCP-HTTP   normal   80   tcp
59 0.181818182 0.181818182        11 Normal-TCP-HTTP   normal   80   tcp
60 0.000000000 0.285714286         7 Normal-TCP-HTTP   normal   80   tcp
61 0.000000000 0.571428571         7 Normal-TCP-HTTP   normal   80   tcp
62 0.000000000 0.507692308        65 Normal-TCP-HTTP   normal  443   tcp
63 0.338983051 0.169491525        59 Normal-TCP-HTTP   normal   80   tcp
64 0.025641026 0.476923077       195 Normal-TCP-HTTP   normal   80   tcp
65 0.002557545 0.498721228       391 Normal-TCP-HTTP   normal   80   tcp
66 0.319148936 0.191489362        47 Normal-TCP-HTTP   normal   80   tcp
 [ reached 'max' / getOption("max.print") -- omitted 2536 rows ]
feature_vectors_cleaned_aux_rest <- feature_vectors_cleaned %>% filter(class != 'Botnet-TCP-SMTP-Attempt-SPAM') %>% filter(class != 'Normal-TCP-HTTP')
feature_vectors_cleaned_aux_rest %>% group_by(class) %>% summarise(n=n()) %>% arrange(desc(n))
# A tibble: 45 x 2
   class                                       n
   <fct>                                   <int>
 1 Botnet-TCP-HTTP-Established-Ad            487
 2 Botnet-TCP-HTTP-Established               377
 3 Botnet-UDP-DNS                            301
 4 Botnet-TCP-HTTP-Established-SSL           210
 5 Botnet-TCP-HTTP-CC-Not-Encrypted           68
 6 Normal-UDP-NTP-server                      67
 7 Botnet-TCP-HTTPS-Established-Microsoft     58
 8 Botnet-TCP-HTTP-Google-Net-Established     50
 9 Botnet-TCP-SMTP-Established-SPAM           49
10 Botnet-TCP-HTTP-CC-Plain-Encrypted-Data    38
# ... with 35 more rows
aux1 <- rbind(feature_vectors_cleaned_aux_botnet[1:500,],feature_vectors_cleaned_aux_normal[1:500,])
aux1 %>% group_by(class) %>% summarise(n=n()) %>% arrange(desc(n))
# A tibble: 2 x 2
  class                            n
  <fct>                        <int>
1 Botnet-TCP-SMTP-Attempt-SPAM   500
2 Normal-TCP-HTTP                500
aux <- rbind(feature_vectors_cleaned_aux_rest,aux1)
aux %>% group_by(class) %>% summarise(n=n()) %>% arrange(desc(n))
# A tibble: 47 x 2
   class                                      n
   <fct>                                  <int>
 1 Botnet-TCP-SMTP-Attempt-SPAM             500
 2 Normal-TCP-HTTP                          500
 3 Botnet-TCP-HTTP-Established-Ad           487
 4 Botnet-TCP-HTTP-Established              377
 5 Botnet-UDP-DNS                           301
 6 Botnet-TCP-HTTP-Established-SSL          210
 7 Botnet-TCP-HTTP-CC-Not-Encrypted          68
 8 Normal-UDP-NTP-server                     67
 9 Botnet-TCP-HTTPS-Established-Microsoft    58
10 Botnet-TCP-HTTP-Google-Net-Established    50
# ... with 37 more rows
feature_vectors_cleaned <- aux

Create training set and testset

set.seed(212)
trainIndex <- createDataPartition(feature_vectors_cleaned$subclass, p=0.70, list=FALSE)
data_training <- feature_vectors_cleaned[ trainIndex,]
data_testing <- feature_vectors_cleaned[-trainIndex,]
#data_train = data_train %>% filter(length>5)
train <- upSample(x = data_training,  y = data_training$subclass, yname="class")
training <- train[,-c(11,16)]
testing <- data_testing[,-c(11)]
training
testing
nrow(training)
[1] 3322
nrow(feature_vectors_cleaned)
[1] 3089

Training configuration

ctrl_fast <- trainControl(method="cv", 
                     repeats=2,
                     number=10, 
                     summaryFunction=twoClassSummary,
                     verboseIter=T,
                     classProbs=TRUE,
                     allowParallel = TRUE)  

Experiment 1

Creation of cluster and k parameters analysis

library(factoextra)
library(cluster)
library(NbClust)
feature_vector_training = training[,-c(11,12,13,14)]
# K-means clustering
set.seed(321)
#km.res <- kmeans(feature_vector_training, 3, nstart = 25)
km.res <- kmeans(feature_vector_training, 7, nstart = 25)
# k-means group number of each observation
km.res$cluster
   [1] 2 1 2 1 1 5 5 4 2 5 5 2 3 3 3 2 1 2 3 2 2 1 5 3 2 1 3 3 3 3 3 6 3 4 2 2 1 5 2 1 7 3 2 1 1 2 1 1 1 1 3 1 3 1 1 1 3 2 2 2 2 2 2 6 2 2 2 2 6 6 5 6 4 4 2 2
  [77] 2 4 4 2 2 2 2 3 6 4 4 2 2 4 4 6 6 2 2 3 4 2 2 2 4 2 2 6 4 3 2 5 2 2 6 2 2 2 2 4 4 2 2 2 5 7 3 6 3 5 6 2 2 3 4 2 6 5 2 4 4 3 2 6 4 4 4 4 3 5 2 4 4 4 4 4
 [153] 4 6 6 4 6 3 4 5 6 4 6 3 4 4 6 4 4 4 6 2 4 4 3 3 4 6 6 5 4 6 3 4 5 6 5 4 3 4 4 4 4 4 6 6 6 6 6 6 3 3 5 4 4 1 2 2 4 2 4 6 5 4 4 2 7 6 6 6 3 6 6 7 3 4 5 6
 [229] 7 4 5 2 6 5 3 1 1 1 6 4 6 4 6 6 5 6 6 6 6 6 6 6 7 5 7 5 1 3 2 1 2 1 2 1 1 1 1 2 2 3 2 5 5 5 1 7 7 7 7 1 3 1 1 2 3 2 2 3 3 1 1 1 1 2 2 1 3 1 1 2 2 3 4 3
 [305] 1 1 1 2 2 3 1 2 1 3 1 2 1 2 1 2 3 2 2 2 2 2 1 1 2 5 5 1 1 5 1 1 1 1 1 1 1 1 1 1 1 6 1 1 6 2 1 1 1 5 2 1 2 5 2 2 1 4 1 6 2 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 [381] 1 1 1 1 1 1 1 1 1 3 2 2 1 1 3 2 1 2 2 2 2 5 1 3 5 3 2 1 2 1 2 2 1 1 1 1 3 1 2 1 5 2 2 1 1 1 3 3 1 1 2 2 2 1 3 2 2 1 1 3 1 2 6 2 6 5 5 5 5 2 2 2 2 2 2 3
 [457] 2 2 2 2 2 2 2 6 1 6 6 6 3 3 6 6 3 6 6 2 1 1 2 1 2 6 4 1 3 2 2 2 3 1 3 2 3 1 1 1 1 1 1 2 2 1 2 1 2 3 1 1 6 2 3 1 1 1 7 1 7 2 3 1 3 3 3 2 2 3 2 1 1 1 1 3
 [533] 1 2 1 2 5 7 4 3 3 3 1 1 2 2 1 2 3 3 2 2 2 1 1 3 1 5 1 3 2 1 1 1 5 1 2 2 3 2 2 2 3 3 3 3 1 2 1 2 2 2 3 3 2 3 1 3 1 1 1 2 1 1 1 1 3 3 3 2 2 1 2 2 2 2 1 1
 [609] 1 6 2 1 1 2 1 1 1 3 1 1 2 2 3 2 1 1 1 1 3 3 1 1 4 2 2 2 1 2 3 2 2 1 5 2 2 1 2 2 1 1 1 2 3 2 2 3 3 3 3 1 1 1 1 1 2 2 2 3 1 1 1 2 2 3 2 1 1 1 3 1 1 4 1 2
 [685] 3 3 2 1 3 3 1 1 1 2 3 5 1 1 1 5 2 2 2 3 1 3 3 1 2 1 1 2 2 2 3 2 1 3 3 1 7 2 3 1 3 2 7 1 2 1 1 2 1 1 1 2 2 3 1 3 1 1 2 1 1 1 3 1 3 2 1 1 1 3 2 1 3 2 4 1
 [761] 1 3 1 2 3 2 1 1 1 1 1 2 1 4 3 3 2 1 1 2 3 2 3 1 1 2 3 2 2 2 2 3 7 2 3 1 3 6 3 1 2 2 2 3 1 1 1 3 1 1 1 1 1 1 1 2 3 2 1 4 1 1 1 3 1 2 1 4 3 3 1 6 2 3 1 1
 [837] 2 1 2 1 1 1 2 1 1 1 1 1 4 1 2 1 7 1 1 1 1 1 2 2 1 1 1 2 1 1 2 2 3 1 1 2 1 2 2 1 1 2 3 3 3 2 3 3 1 1 1 1 2 1 1 2 2 2 1 1 3 1 1 1 1 2 1 3 3 2 2 2 2 1 2 1
 [913] 3 1 5 2 1 1 1 1 2 2 4 2 1 1 3 2 2 2 1 3 2 1 1 1 3 3 2 3 3 1 1 1 2 1 1 1 1 3 3 1 3 3 2 1 1 1 1 1 2 2 1 2 1 3 2 1 2 2 3 2 2 2 5 3 2 2 2 5 1 1 1 1 1 2 2 1
 [989] 1 1 1 3 1 1 1 3 1 2 1 3
 [ reached getOption("max.print") -- omitted 2322 entries ]
# Visualize k-means clusters
fviz_cluster(km.res, data = feature_vector_training, geom = "point",
             stand = FALSE, ellipse.type = "norm")

Elbow analysis

set.seed(321)
# Compute and plot wss for k = 2 to k = 15
k.max <- 15 # Maximal number of clusters
data <- feature_vector_training
wss <- sapply(1:k.max, 
        function(k){kmeans(data, k, nstart=10 )$tot.withinss})
plot(1:k.max, wss,
       type="b", pch = 19, frame = FALSE, 
       xlab="Number of clusters K",
       ylab="Total within-clusters sum of squares")
abline(v = 3, lty =2)

Silhouette analysis

set.seed(322)
k.max <- 10
data <- feature_vector_training
nrow(data)
[1] 3322
sil <- rep(0, k.max)
# Compute the average silhouette width for 
# k = 2 to k = 15
for(i in 2:k.max){
  km.res <- kmeans(data, centers = i, nstart = 25)
  ss <- silhouette(km.res$cluster, dist(data))
  sil[i] <- mean(ss[, 3])
}
# Plot the  average silhouette width
plot(1:k.max, sil, type = "b", pch = 19, 
     frame = FALSE, xlab = "Number of clusters k")
abline(v = which.max(sil), lty = 2)

Useful functions

cold_start_data <- function(training.sampled,testing,settings){
  library(doParallel)
  cl <- makeCluster(2)
  registerDoParallel(cl)
  size_training <- nrow(training.sampled)
  split_size_training = size_training / 200
  testing_result = data.frame(numeric(nrow(testing)))
  
  count_random <- foreach(i=1:split_size_training) %dopar% {
    200 * i
  }
  metric <- numeric(split_size_training)
  metric_t <- numeric(split_size_training)
  #metric <- foreach(i=1:split_size_training) %do% {
  for(i in c(1:split_size_training)){
    #library(caret)
    #library(dplyr)
    count <- 200 * i
    aux_training_set <- training.sampled[c(1:count), ]#training[sample(size_training, count), ]
    clusters <- kmeans(aux_training_set[,-c(11,12,13,14)],3,nstart = 25)
    aux_training_set_cluster <- cbind(aux_training_set, cluster = clusters$cluster)
    result_vector <- numeric(nrow(testing))
    result_vector_trainning <- numeric(nrow(aux_training_set))
    
    for (j in c(1:3)){
      cluster_data <- dplyr::filter(aux_training_set_cluster, cluster == j)
      new_rfFit <- train(subclass ~ sp+wp+wnp+snp+ds+dm+dl+ss+sm+sl,
                 data = cluster_data,
                 metric="ROC",
                 method = "rf",
                 trControl = settings)
      #Testing predict
      predsrfprobs <- predict(new_rfFit,testing,type='prob')
      
      for (k in c(1:length(result_vector))){
        if(predsrfprobs$botnet[k] > 0.5){
          result_vector[k] <- result_vector[k] + 1
        }
        else{
          result_vector[k] <- result_vector[k] - 1
        }
      }
      
      #Trainning predict
      predsrfprobs_t <- predict(new_rfFit,aux_training_set,type='prob')
      for (k in c(1:length(result_vector_trainning))){
        if(predsrfprobs_t$botnet[k] > 0.5){
          result_vector_trainning[k] <- result_vector_trainning[k] + 1
        }
        else{
          result_vector_trainning[k] <- result_vector_trainning[k] - 1
        }
      }
    }
    a = ifelse(result_vector > 0,'botnet','normal')
    b <- ifelse(result_vector_trainning > 0,'botnet','normal')
    testing_result <- cbind(testing_result,'result' = result_vector)
    cm <- confusionMatrix(a,testing$subclass)
    metric[i] <- cm$byClass['F1']#cm$overall[1]
    
    cm_t <- confusionMatrix(b,aux_training_set$subclass)
    metric_t[i] <- cm_t$byClass['F1']
    #list('metric' = metric, 'metric_t' = metric_t)
  }
  output <- do.call(rbind, Map(data.frame, data_count=count_random, metric=metric))
  output_t <- do.call(rbind, Map(data.frame, data_count=count_random, metric=metric_t))
  list_result <- list('output' = output, 'output_t' = output_t, 'testing_result' = testing_result)
}
cold_start_data_only_rf <- function(training.sampled,testing,settings){
  size_training <- nrow(training.sampled)
  split_size_training = size_training / 200
  testing_result = data.frame(numeric(nrow(testing)))
  
  count_random <- foreach(i=1:split_size_training) %dopar% {
    200 * i
  }
  metric <- numeric(split_size_training)
  metric_t <- numeric(split_size_training)
  #metric <- foreach(i=1:split_size_training) %do% {
  for(i in c(1:split_size_training)){
    #library(caret)
    #library(dplyr)
    count <- 200 * i
    aux_training_set <- training.sampled[c(1:count), ]#training[sample(size_training, count), ]
    new_rfFit <- train(subclass ~ sp+wp+wnp+snp+ds+dm+dl+ss+sm+sl,
                 data = aux_training_set,
                 metric="ROC",
                 method = "rf",
                 trControl = settings)
    #Testing predict
    predsrfprobs <- predict(new_rfFit,testing,type='prob')
    predsrf <- ifelse(predsrfprobs$botnet >=0.5,'botnet','normal')
    cm <- confusionMatrix(predsrf,testing$subclass)
    metric[i] <- cm$byClass['F1']
    
    
    #Trainning predict
    predsrfprobs_t <- predict(new_rfFit,aux_training_set,type='prob')
    predsrf_t <- ifelse(predsrfprobs_t$botnet >= 0.5,'botnet','normal')
    cm_t <- confusionMatrix(predsrf_t,aux_training_set$subclass)
    metric_t[i] <- cm_t$byClass['F1']
    
  }
  output <- do.call(rbind, Map(data.frame, data_count=count_random, metric=metric))
  output_t <- do.call(rbind, Map(data.frame, data_count=count_random, metric=metric_t))
  list_result <- list('output' = output, 'output_t' = output_t, 'testing_result' = testing_result)
}
generate_data_noisy <- function(dataset, porcent){
  list_aux <- sample(nrow(dataset) ,porcent)
  noisy_data_sample <- dataset[list_aux,]
  no_noisy_data_sample <- dataset[-list_aux,]
  
  noisy_data_sample_b <- noisy_data_sample %>% filter(class == 'Botnet')
  noisy_data_sample_n <- noisy_data_sample %>% filter(class == 'Normal')
  
  noisy_data_sample_b$class <- as.character(noisy_data_sample_b$class)
  noisy_data_sample_b$class[noisy_data_sample_b$class == 'Botnet'] <- 'Normal'
  noisy_data_sample_b$class <- as.factor(noisy_data_sample_b$class)
  
  noisy_data_sample_n$class <- as.character(noisy_data_sample_n$class)
  noisy_data_sample_n$class[noisy_data_sample_n$class == 'Normal'] <- 'Botnet'
  noisy_data_sample_n$class <- as.factor(noisy_data_sample_n$class)
  
  noisy_data <- rbind(noisy_data_sample_b, noisy_data_sample_n)
  training_noisy <- rbind(no_noisy_data_sample,noisy_data)
  training_noisy <- training_noisy[sample(nrow(training_noisy),nrow(training_noisy)),]
  return(training_noisy)
}
get_ELA_measure <- function(A0, Ax){
  RLA <- (A0 - Ax) / A0
  FA0 <- (100 - A0) / A0
  ELA <- RLA + FA0
  return(ELA)
}
randomForest_performace <- function(training_data, testing_data){
  rfFit <- train(class ~ sp+wp+wnp+snp+ds+dm+dl+ss+sm+sl,
                 data = training_data,
                 metric="ROC",
                 method = "rf",
                 trControl = settings)
  predsrfprobs <- predict(rfFit,testing_data,type='prob')
  predsrf <- ifelse(predsrfprobs$Botnet >=0.5,'Botnet','Normal')
  cm <- confusionMatrix(predsrf,testing_data$class)
  result <- cm$byClass
  return(result)
}
training
testing

Data training partitions: cold start study

Iteration #1

output_1 <- result$output
output_t_1 <- result$output_t
output_1

gg <- ggplot(data = output_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

first_training_sample <- training.sampled_1[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

output_t_aux_1 <- output_t_1
names(output_t_aux_1) <- c('data_count_t','metric_t')
output_result_1 <- cbind(output_1,output_t_aux_1)
gg <- ggplot(data = output_result_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #2

output_2 <- result_2$output
output_t_2 <- result_2$output_t
output_2

gg <- ggplot(data = output_2)
  gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
    labs(title="Random Forest through data training size", 
         #subtitle="Drawn from Long Data format", 
         caption="Source: CTU-13", 
         y="F1 Score", 
         color=NULL)

first_training_sample <- training.sampled_2[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_2 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

output_t_aux_2 <- output_t_2
names(output_t_aux_2) <- c('data_count_t','metric_t')
output_result_2 <- cbind(output_2,output_t_aux_2)
gg <- ggplot(data = output_result_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #3

output_3 <- result_3$output
output_t_3 <- result_3$output_t
output_3

gg <- ggplot(data = output_3)
  gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
    labs(title="Random Forest through data training size", 
         #subtitle="Drawn from Long Data format", 
         caption="Source: CTU-13", 
         y="F1 Score", 
         color=NULL)

first_training_sample <- training.sampled_3[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_3 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

output_t_aux_3 <- output_t_3
names(output_t_aux_3) <- c('data_count_t','metric_t')
output_result_3 <- cbind(output_3,output_t_aux_3)
gg <- ggplot(data = output_result_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #4

output_4 <- result_4$output
output_t_4 <- result_4$output_t
output_4

gg <- ggplot(data = output_4)
  gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
    labs(title="Random Forest through data training size", 
         #subtitle="Drawn from Long Data format", 
         caption="Source: CTU-13", 
         y="F1 Score", 
         color=NULL)

first_training_sample <- training.sampled_4[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_4 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

output_t_aux_4 <- output_t_4
names(output_t_aux_4) <- c('data_count_t','metric_t')
output_result_4 <- cbind(output_4,output_t_aux_4)
gg <- ggplot(data = output_result_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #5

output_5 <- result_5$output
output_t_5 <- result_5$output_t
output_5

gg <- ggplot(data = output_5)
  gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
    labs(title="Random Forest through data training size", 
         #subtitle="Drawn from Long Data format", 
         caption="Source: CTU-13", 
         y="F1 Score", 
         color=NULL)

first_training_sample <- training.sampled_5[1:200,]
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

testing_result_5 <- result$testing_result
#testing_result
gg <- ggplot(data = output_t_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

output_t_aux_5 <- output_t_5
names(output_t_aux_5) <- c('data_count_t','metric_t')
output_result_5 <- cbind(output_5,output_t_aux_5)
gg <- ggplot(data = output_result_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Data training partitions: cold start study (simple Random Forest)

Iteration #1

rf_output_1 <- rf_result_1$output
rf_output_t_1 <- rf_result_1$output_t
rf_output_1
gg <- ggplot(data = rf_output_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_first_training_sample <- rf_training.sampled_1[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_1 <- rf_result_1$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_output_t_aux_1 <- rf_output_t_1
names(rf_output_t_aux_1) <- c('data_count_t','metric_t')
rf_output_result_1 <- cbind(rf_output_1,rf_output_t_aux_1)
gg <- ggplot(data = rf_output_result_1)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #2

rf_output_2 <- rf_result_2$output
rf_output_t_2 <- rf_result_2$output_t
rf_output_2
gg <- ggplot(data = rf_output_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_first_training_sample <- rf_training.sampled_2[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_output_t_aux_2 <- rf_output_t_2
names(rf_output_t_aux_2) <- c('data_count_t','metric_t')
rf_output_result_2 <- cbind(rf_output_2,rf_output_t_aux_2)
gg <- ggplot(data = rf_output_result_2)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #3

rf_output_3 <- rf_result_3$output
rf_output_t_3 <- rf_result_3$output_t
rf_output_3
gg <- ggplot(data = rf_output_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_first_training_sample <- rf_training.sampled_3[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_output_t_aux_3 <- rf_output_t_3
names(rf_output_t_aux_3) <- c('data_count_t','metric_t')
rf_output_result_3 <- cbind(rf_output_3,rf_output_t_aux_3)
gg <- ggplot(data = rf_output_result_3)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #4

rf_output_4 <- rf_result_4$output
rf_output_t_4 <- rf_result_4$output_t
rf_output_4
gg <- ggplot(data = rf_output_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_first_training_sample <- rf_training.sampled_4[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_output_t_aux_4 <- rf_output_t_4
names(rf_output_t_aux_4) <- c('data_count_t','metric_t')
rf_output_result_4 <- cbind(rf_output_4,rf_output_t_aux_4)
gg <- ggplot(data = rf_output_result_4)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Iteration #5

rf_output_5 <- rf_result_5$output
rf_output_t_5 <- rf_result_5$output_t
rf_output_5
gg <- ggplot(data = rf_output_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_first_training_sample <- rf_training.sampled_5[1:200,]
ggplot(rf_first_training_sample) + geom_bar(aes(subclass))

rf_class_distribution <- rf_first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(rf_first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

#rf_testing_result_2 <- rf_result_2$testing_result
#testing_result
gg <- ggplot(data = rf_output_t_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

rf_output_t_aux_5 <- rf_output_t_5
names(rf_output_t_aux_5) <- c('data_count_t','metric_t')
rf_output_result_5 <- cbind(rf_output_5,rf_output_t_aux_5)
gg <- ggplot(data = rf_output_result_5)
gg + geom_line(aes(x = data_count, y = metric),color = 'red') + geom_line(aes(x = data_count_t, y = metric_t),color = 'blue') + 
  labs(title="Random Forest through data training size", 
       #subtitle="Drawn from Long Data format", 
       caption="Source: CTU-13", 
       y="F1 Score", 
       color=NULL)

Studies Samples

first_training_sample <- training.sampled[1:200,]
first_training_sample
ggplot(first_training_sample) + geom_bar(aes(subclass))

class_distribution <- first_training_sample %>% group_by(class) %>% summarise(n = n()) %>% arrange(desc(n))
ggplot(first_training_sample) + geom_bar(aes(class)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

part 2

Test with only one

set.seed(226)
size_training <- nrow(training)
training.sampled <- training[sample(size_training, size_training), ]

aux_training_set <- training.sampled[c(1:200), ]#training[sample(size_training, 200), ]
clusters <- kmeans(aux_training_set[,-c(11,12,13,14)],3,nstart = 25)
aux_training_set_cluster <- cbind(aux_training_set, cluster = clusters$cluster)
result_vector <- numeric(nrow(testing))
result_vector_trainning <- numeric(nrow(aux_training_set))

for (j in c(1:3)){
  cluster_data <- aux_training_set_cluster %>% filter(cluster == j)
  new_rfFit <- train(subclass ~ sp+wp+wnp+snp+ds+dm+dl+ss+sm+sl,
               data = cluster_data,
               metric="ROC",
               method = "rf",
               trControl = ctrl_fast)
  predsrfprobs <- predict(new_rfFit,testing,type='prob')
  for (k in c(1:length(result_vector))){
    if(predsrfprobs$botnet[k] > 0.5){
      result_vector[k] <- result_vector[k] + 1
    }
    else{
      result_vector[k] <- result_vector[k] - 1
    }
  }
  
  #Trainning predict
  predsrfprobs_t <- predict(new_rfFit,aux_training_set,type='prob')
  for (k in c(1:length(result_vector_trainning))){
    if(predsrfprobs_t$botnet[k] > 0.5){
      result_vector_trainning[k] <- result_vector_trainning[k] + 1
    }
    else{
      result_vector_trainning[k] <- result_vector_trainning[k] - 1
    }
  }
}

a = ifelse(result_vector > 0,'botnet','normal')
b <- ifelse(result_vector_trainning > 0,'botnet','normal')
cm <- confusionMatrix(a,testing$subclass)
metric <- cm$byClass['F1']#cm$overall[1]
metric
cm_t <- confusionMatrix(b,aux_training_set$subclass)
metric_t <- cm_t$byClass['F1']
metric_t

Sample examples

set.seed(556)
a = c(1,2,3,4,5,6,7,8,9)
r <- sample(9,3)
a[r]
r2 <- sample(9,3)
a[r2]
#testing_result
testing_result.bkp <- testing_result
testing_result
names_aux <- foreach(i=1:(nrow(training)/200)) %do% {
    iteration <- 200 * i
    paste('size_',toString(iteration),sep = "")
}
testing_result_names <- unlist(names_aux, use.names=FALSE)
testing_result <- testing_result[,c(-1)]
names(testing_result) <- testing_result_names
testing_result

testing_aux <- cbind(testing,testing_result)
testing_aux.bkp2 <- testing_aux
#write.table(testing_aux,file="testing_cluster_result.txt",sep="|", row.names = F)
testing_aux
sums <- rowSums(testing_aux[,-c(1:14)])
sums
testing_aux[,-c(1:14)]
testing_aux <- cbind(testing_aux,sums)
testing_aux
testing_aux_result <- testing_aux %>% group_by(class) %>% summarise(n = n(), sums = sum(sums)) %>% arrange(desc(sums))
testing_aux_result

graph_testing_result <- ggplot(testing_aux_result[-c(1,nrow(testing_aux_result)),])
graph_testing_result + geom_point(aes(class,sums)) + theme(axis.text.x = element_text(angle = 90, hjust = 1))

feature_vectors_cleaned

library(gridExtra)
pdf("data_output.pdf", height=11, width=8.5)
grid.table(feature_vectors_cleaned[1:20,])
dev.off()

testing_result.bkp
testing_aux.bkp2
testing_aux_result

rusty_data_result <- testing_aux.bkp2
rusty_data_result_short <- rusty_data_result[,-c(1:11,14)]
rusty_data_result_short[,-c(1,2)]
rusty_data_result_short$pos <- rowSums(rusty_data_result_short[,-c(1,2)] > 0)
rusty_data_result_short$neg <- rowSums(rusty_data_result_short[,-c(1,2)] < 0)
rusty_data_result_short_cleaned <- rusty_data_result_short[,c(1,2,46,47)]
rusty_data_result_short_cleaned
rusty_data_result_short_cleaned_result <- rusty_data_result_short_cleaned %>% mutate(good = ifelse(subclass == 'normal',neg,pos))
rusty_data_result_short_cleaned_result <- rusty_data_result_short_cleaned_result %>% mutate(bad = ifelse(subclass == 'normal',pos,neg))
rusty_data_result_short_cleaned_result %>% group_by(port) %>% summarise(n=n(),good = sum(good),bad = sum(bad)) %>% arrange(desc(n))

data_botnet_port <- rusty_data_result_short_cleaned_result %>% filter(subclass == 'botnet')
data_normal_port <- rusty_data_result_short_cleaned_result %>% filter(subclass == 'normal')
data_botnet_port_result <-  data_botnet_port %>% group_by(port) %>% summarise(n=n(),good = sum(good),bad = sum(bad)) %>% arrange(desc(n))
data_normal_port_result <- data_normal_port %>% group_by(port) %>% summarise(n=n(),good = sum(good),bad = sum(bad)) %>% arrange(desc(n))
data_botnet_port_result
data_normal_port_result

ggplot(data = data_botnet_port_result) + 
  geom_bar(mapping = aes(x = port, fill = clarity))

#write.table(data_botnet_port_result,file="data_botnet_port.txt",sep="|", row.names = F)
library(reshape2)
data <- data_botnet_port_result
data$port <- as.factor(data$port)

melt(data[,c(1,3,4)])

ggplot(melt(data[,c(1,3,4)]))+
  geom_col(aes(x=port,y=value,fill=variable))+
  #theme_bw()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Making Noisy data (training_noisy: dataset to train with 20% of noisy)

set.seed(101) 
training.bkp <- training
noisy_data <- training

porcent <- nrow(training) / 5
training_noisy <- generate_data_noisy(noisy_data,porcent)
nrow(training)
nrow(training_noisy)
cm$overall[1]
 Accuracy 
0.9222042 

Robustness Analisys(one simple iteration)

rf_measures_result
 [1]         NA 0.92433697         NA 0.92199688         NA 0.92043682         NA 0.91341654
 [9]         NA 0.91809672         NA 0.91107644         NA 0.91575663         NA 0.91809672
[17]         NA 0.90951638         NA 0.91185647         NA 0.91107644         NA 0.90249610
[25]         NA 0.90405616         NA 0.90171607         NA 0.87051482         NA 0.88845554
[33]         NA 0.86739470         NA 0.84243370         NA 0.85179407         NA 0.78549142
[41]         NA 0.72074883         NA 0.74726989         NA 0.66458658         NA 0.58346334
[49]         NA 0.48673947         NA 0.40483619         NA 0.30109204         NA 0.22308892
[57]         NA 0.24258970         NA 0.18798752         NA 0.14664587         NA 0.13182527
[65]         NA 0.12792512         NA 0.12090484         NA 0.12792512         NA 0.11310452
[73]         NA 0.09438378         NA 0.09438378         NA 0.09282371         NA 0.08346334
[81]         NA 0.09516381         NA 0.09438378         NA 0.08658346         NA 0.08112324
[89]         NA 0.07878315

Robustness Analisys by port(One simple Iteration)

Robustness Analisys: ploting accuracy

index <- seq(2,90,2)
measure_result <- rf_measures_result[index]
rla_measure_data <- data.frame(index,measure_result)
names(rla_measure_data) <- c('noise_porcent','balanced_accuracy')

g<-ggplot(rla_measure_data) + geom_point(mapping = aes(x = noise_porcent, y = balanced_accuracy)) + geom_smooth(mapping = aes(x = noise_porcent, y = balanced_accuracy))
ggplotly(g)

Robustness Analisys: ploting ELA measure

index <- seq(2,90,2)
measure_result <- ela_measures_result[index]
ela_measure_data <- data.frame(index,measure_result)
names(ela_measure_data) <- c('noise_porcent','ela_measure')

ggplot(ela_measure_data) + geom_point(mapping = aes(x = noise_porcent, y = ela_measure)) + geom_smooth(mapping = aes(x = noise_porcent, y = ela_measure))

Robustness Analisys(30 iterations)

result_ela_measure
Error: object 'result_ela_measure' not found
result_ela_measure.bkp
Error: object 'result_ela_measure.bkp' not found

Cosine Similarity

prediction_vector
 [1] "0"                "0"                "0.1428571"        "0.1428571"        "0"                "0"                "0.5714286"       
 [8] "0"                "0"                "0.5714286"        "Normal"           "From-Normal-Jist" "80"               "tcp"             

cs_data.result <- data.frame(rf_result_5$output$data_count)
#for(i in c(1:1)){
  current_seed <- 226 #+ i
  set.seed(current_seed)
  
  size_training <- nrow(training)
  cs_training.sampled_current <- training[sample(size_training, size_training), ]
  split_size_training = size_training / 200
  metric <- numeric(split_size_training)
  for(j in 1:split_size_training){
    count <- 200 * j
    aux_training_set <- cs_training.sampled_current[c(1:count), ]
    result <- c()
    for(k in 1:nrow(testing)){
      prediction_vector <- testing[k,]
      prediction_vector <- as.vector(as.matrix(prediction_vector))
      output_result <- prediction_by_similarity(aux_training_set,prediction_vector,101)
      result[k] <- output_result
    }
    vector_result <- unlist(result)
    cm <- confusionMatrix(vector_result,testing$class)
    metric[j] <- cm$byClass['F1']
    
  }
  cs_data.result <- cbind(cs_data.result, metric)
#}
cs_data.result
for(i in c(1:30)){
 current_seed <- 226 + i
 set.seed(current_seed)
 size_training <- nrow(training)
 rf_training.sampled_current <- training[sample(size_training, size_training), ]
 
 print_data = rf_training.sampled_current[,c(1:10,14)]
 file_name = paste(paste("trainin_sample", i, sep = '_'), 'csv', sep = '.')
 write.csv(print_data,file=file_name , row.names = F)
}
 
 #write.csv(testing[,c(1:11)], file='testing.csv', row.names = F)

```

LS0tCnRpdGxlOiAiQ0FJJ3MgZXhwZXJpbWVudHMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBMaWJyYXJ5IEVudmlyb25tZW50CmBgYHtyfQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkodGlkeXZlcnNlKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHN0cmluZ3IpKQojc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KElTTFIpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoY2FyZXQpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZG9NQykpCiNzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkocGxvdGx5KSkKI3N1cHByZXNzTWVzc2FnZXMobGlicmFyeShzdHJpbmdyKSkKcmVnaXN0ZXJEb01DKGNvcmVzPTQpCmBgYAoKIyMjIExvYWQgYW5kIHByb2Nlc3NpbmcgZGF0YSBjdHUxMyBjbGVhbmVkCmBgYHtyfQpteURhdGFfY2xlYW5lZCA8LSByZWFkLmNzdignL2hvbWUvamd1ZXJyYS9kYXRhc2V0cy9jdHUxMy5sYWJlbGVkLmNsZWFuZWQnLCBzdHJpbmdzQXNGYWN0b3JzID0gRiwgc2VwID0gJ3wnKQpteURhdGFfY2xlYW5lZC5ia3AgPSBteURhdGFfY2xlYW5lZApteURhdGFfY2xlYW5lZAoKI1BlcmlvZGljaXR5Cm15RGF0YV9jbGVhbmVkID0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShzdHJvbmdfcCA9IHN0cl9jb3VudChTdGF0ZSwnW2EtaV0nKSkKbXlEYXRhX2NsZWFuZWQgPSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHdlYWtfcCA9IHN0cl9jb3VudChTdGF0ZSwnW0EtSV0nKSkKbXlEYXRhX2NsZWFuZWQgPSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHdlYWtfbnAgPSBzdHJfY291bnQoU3RhdGUsJ1tyLXpdJykpCm15RGF0YV9jbGVhbmVkID0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShzdHJvbmdfbnAgPSBzdHJfY291bnQoU3RhdGUsJ1tSLVpdJykpCiNEdXJhdGlvbgpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fcyA9IHN0cl9jb3VudChTdGF0ZSwnKGF8QXxyfFJ8MXxkfER8dXxVfDR8Z3xHfHh8WHw3KScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fbSA9IHN0cl9jb3VudChTdGF0ZSwnKGJ8QnxzfFN8MnxlfEV8dnxWfDV8aHxIfHl8WXw4KScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fbCA9IHN0cl9jb3VudChTdGF0ZSwnKGN8Q3x0fFR8M3xmfEZ8d3xXfDZ8aXxJfHp8Wnw5KScpKQojU2l6ZQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc2l6ZV9zID0gc3RyX2NvdW50KFN0YXRlLCdbYS1jXScpICsgc3RyX2NvdW50KFN0YXRlLCdbQS1DXScpICsgc3RyX2NvdW50KFN0YXRlLCdbci10XScpICsgc3RyX2NvdW50KFN0YXRlLCdbUi1UXScpICsgc3RyX2NvdW50KFN0YXRlLCdbMS0zXScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc2l6ZV9tID0gc3RyX2NvdW50KFN0YXRlLCdbZC1mXScpICsgc3RyX2NvdW50KFN0YXRlLCdbRC1GXScpICsgc3RyX2NvdW50KFN0YXRlLCdbdS13XScpICsgc3RyX2NvdW50KFN0YXRlLCdbVS1XXScpICsgc3RyX2NvdW50KFN0YXRlLCdbNC02XScpKQpteURhdGFfY2xlYW5lZCA9IG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc2l6ZV9sID0gc3RyX2NvdW50KFN0YXRlLCdbZy1pXScpICsgc3RyX2NvdW50KFN0YXRlLCdbRy1JXScpICsgc3RyX2NvdW50KFN0YXRlLCdbeC16XScpICsgc3RyX2NvdW50KFN0YXRlLCdbWC1aXScpICsgc3RyX2NvdW50KFN0YXRlLCdbNy05XScpKQoKI1BlcmlvZGljaXR5ICUKbXlEYXRhX2NsZWFuZWQgPC0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShzdHJvbmdfcCA9IChzdHJvbmdfcCAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUod2Vha19wID0gKHdlYWtfcCAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoc3Ryb25nX25wID0gKHN0cm9uZ19ucCAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUod2Vha19ucCA9ICh3ZWFrX25wIC8gbW9kZWxzaXplKSkKI0R1cmF0aW9uICUKbXlEYXRhX2NsZWFuZWQgPC0gbXlEYXRhX2NsZWFuZWQgJT4lIG11dGF0ZShkdXJhdGlvbl9zID0gKGR1cmF0aW9uX3MgLyBtb2RlbHNpemUpKQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKGR1cmF0aW9uX20gPSAoZHVyYXRpb25fbSAvIG1vZGVsc2l6ZSkpCm15RGF0YV9jbGVhbmVkIDwtIG15RGF0YV9jbGVhbmVkICU+JSBtdXRhdGUoZHVyYXRpb25fbCA9IChkdXJhdGlvbl9sIC8gbW9kZWxzaXplKSkKI1NpemUgJQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHNpemVfcyA9IChzaXplX3MgLyBtb2RlbHNpemUpKQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHNpemVfbSA9IChzaXplX20gLyBtb2RlbHNpemUpKQpteURhdGFfY2xlYW5lZCA8LSBteURhdGFfY2xlYW5lZCAlPiUgbXV0YXRlKHNpemVfbCA9IChzaXplX2wgLyBtb2RlbHNpemUpKQoKI01ha2luZyBmZWF0dXJlIHZlY3RvcnMKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQgPSBteURhdGFfY2xlYW5lZFssYygnc3Ryb25nX3AnLCd3ZWFrX3AnLCd3ZWFrX25wJywnc3Ryb25nX25wJywnZHVyYXRpb25fcycsJ2R1cmF0aW9uX20nLCdkdXJhdGlvbl9sJywnc2l6ZV9zJywnc2l6ZV9tJywnc2l6ZV9sJywnbW9kZWxzaXplJywnbGFiZWwnLCdjbGFzcycsJ3BvcnQnLCdwcm90bycpXQpuYW1lcyhmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCkgPSBjKCJzcCIsIndwIiwid25wIiwic25wIiwiZHMiLCJkbSIsImRsIiwic3MiLCJzbSIsInNsIiwibW9kZWxzaXplIiwiY2xhc3MiLCJzdWJjbGFzcyIsInBvcnQiLCJwcm90byIpCmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkJGNsYXNzID0gZmFjdG9yKGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkJGNsYXNzKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCRzdWJjbGFzcyA9IGZhY3RvcihmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCRzdWJjbGFzcykKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQkcHJvdG8gPSBmYWN0b3IoZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQkcHJvdG8pCgpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZAoKYGBgCgojIyMgUmVtb3ZpbmcgZXhjZXNpdmUgQm90bmV0IGFuZCBOb3JtYWwgY2xhc3MoTWFraW5nIHRoZSBkYXRhc2V0IG1vcmUgZXF1aXRhYmxlKQpgYGB7cn0KZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWQuYmtwIDwtIGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkCmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcmlzZShuPW4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRfYXV4X2JvdG5ldCA8LSBmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCAlPiUgZmlsdGVyKGNsYXNzID09ICdCb3RuZXQtVENQLVNNVFAtQXR0ZW1wdC1TUEFNJykKZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRfYXV4X25vcm1hbCA8LSBmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCAlPiUgZmlsdGVyKGNsYXNzID09ICdOb3JtYWwtVENQLUhUVFAnKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZF9hdXhfYm90bmV0CmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkX2F1eF9ub3JtYWwKCmZlYXR1cmVfdmVjdG9yc19jbGVhbmVkX2F1eF9yZXN0IDwtIGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkICU+JSBmaWx0ZXIoY2xhc3MgIT0gJ0JvdG5ldC1UQ1AtU01UUC1BdHRlbXB0LVNQQU0nKSAlPiUgZmlsdGVyKGNsYXNzICE9ICdOb3JtYWwtVENQLUhUVFAnKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZF9hdXhfcmVzdCAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmF1eDEgPC0gcmJpbmQoZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRfYXV4X2JvdG5ldFsxOjUwMCxdLGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkX2F1eF9ub3JtYWxbMTo1MDAsXSkKYXV4MSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2Uobj1uKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmF1eCA8LSByYmluZChmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZF9hdXhfcmVzdCxhdXgxKQphdXggJT4lIGdyb3VwX2J5KGNsYXNzKSAlPiUgc3VtbWFyaXNlKG49bigpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZCA8LSBhdXgKI3dyaXRlLnRhYmxlKGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkLCcvaG9tZS9qZ3VlcnJhL2RhdGFzZXRzL3N0cmF0b3NwaGVyZS9jdHVfMTNfZmVhdHVyZV92ZWN0b3JfY2xlYW5lZC50eHQnLHNlcCA9ICd8Jywgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMjIENyZWF0ZSB0cmFpbmluZyBzZXQgYW5kIHRlc3RzZXQKYGBge3J9CnNldC5zZWVkKDIxMikKdHJhaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkJHN1YmNsYXNzLCBwPTAuNzAsIGxpc3Q9RkFMU0UpCmRhdGFfdHJhaW5pbmcgPC0gZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRbIHRyYWluSW5kZXgsXQpkYXRhX3Rlc3RpbmcgPC0gZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRbLXRyYWluSW5kZXgsXQoKI2RhdGFfdHJhaW4gPSBkYXRhX3RyYWluICU+JSBmaWx0ZXIobGVuZ3RoPjUpCnRyYWluIDwtIHVwU2FtcGxlKHggPSBkYXRhX3RyYWluaW5nLCAgeSA9IGRhdGFfdHJhaW5pbmckc3ViY2xhc3MsIHluYW1lPSJjbGFzcyIpCgp0cmFpbmluZyA8LSB0cmFpblssLWMoMTEsMTYpXQp0ZXN0aW5nIDwtIGRhdGFfdGVzdGluZ1ssLWMoMTEpXQp0cmFpbmluZwp0ZXN0aW5nCgpucm93KHRyYWluaW5nKQpucm93KGZlYXR1cmVfdmVjdG9yc19jbGVhbmVkKQoKYGBgCgojIyMgVHJhaW5pbmcgY29uZmlndXJhdGlvbgpgYGB7cn0KY3RybF9mYXN0IDwtIHRyYWluQ29udHJvbChtZXRob2Q9ImN2IiwgCiAgICAgICAgICAgICAgICAgICAgIHJlcGVhdHM9MiwKICAgICAgICAgICAgICAgICAgICAgbnVtYmVyPTEwLCAKICAgICAgICAgICAgICAgICAgICAgc3VtbWFyeUZ1bmN0aW9uPXR3b0NsYXNzU3VtbWFyeSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZUl0ZXI9VCwKICAgICAgICAgICAgICAgICAgICAgY2xhc3NQcm9icz1UUlVFLAogICAgICAgICAgICAgICAgICAgICBhbGxvd1BhcmFsbGVsID0gVFJVRSkgIApgYGAKCiMjIyBFeHBlcmltZW50IDEKIyMgQ3JlYXRpb24gb2YgY2x1c3RlciBhbmQgayBwYXJhbWV0ZXJzIGFuYWx5c2lzCmBgYHtyfQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkoY2x1c3RlcikKbGlicmFyeShOYkNsdXN0KQpmZWF0dXJlX3ZlY3Rvcl90cmFpbmluZyA9IHRyYWluaW5nWywtYygxMSwxMiwxMywxNCldCiMgSy1tZWFucyBjbHVzdGVyaW5nCnNldC5zZWVkKDMyMSkKI2ttLnJlcyA8LSBrbWVhbnMoZmVhdHVyZV92ZWN0b3JfdHJhaW5pbmcsIDMsIG5zdGFydCA9IDI1KQprbS5yZXMgPC0ga21lYW5zKGZlYXR1cmVfdmVjdG9yX3RyYWluaW5nLCA3LCBuc3RhcnQgPSAyNSkKIyBrLW1lYW5zIGdyb3VwIG51bWJlciBvZiBlYWNoIG9ic2VydmF0aW9uCmttLnJlcyRjbHVzdGVyCgojIFZpc3VhbGl6ZSBrLW1lYW5zIGNsdXN0ZXJzCmZ2aXpfY2x1c3RlcihrbS5yZXMsIGRhdGEgPSBmZWF0dXJlX3ZlY3Rvcl90cmFpbmluZywgZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICBzdGFuZCA9IEZBTFNFLCBlbGxpcHNlLnR5cGUgPSAibm9ybSIpCmBgYAojIyMgRWxib3cgYW5hbHlzaXMKYGBge3J9CnNldC5zZWVkKDMyMSkKIyBDb21wdXRlIGFuZCBwbG90IHdzcyBmb3IgayA9IDIgdG8gayA9IDE1CmsubWF4IDwtIDE1ICMgTWF4aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMKZGF0YSA8LSBmZWF0dXJlX3ZlY3Rvcl90cmFpbmluZwp3c3MgPC0gc2FwcGx5KDE6ay5tYXgsIAogICAgICAgIGZ1bmN0aW9uKGspe2ttZWFucyhkYXRhLCBrLCBuc3RhcnQ9MTAgKSR0b3Qud2l0aGluc3N9KQpwbG90KDE6ay5tYXgsIHdzcywKICAgICAgIHR5cGU9ImIiLCBwY2ggPSAxOSwgZnJhbWUgPSBGQUxTRSwgCiAgICAgICB4bGFiPSJOdW1iZXIgb2YgY2x1c3RlcnMgSyIsCiAgICAgICB5bGFiPSJUb3RhbCB3aXRoaW4tY2x1c3RlcnMgc3VtIG9mIHNxdWFyZXMiKQphYmxpbmUodiA9IDMsIGx0eSA9MikKYGBgCiMjIFNpbGhvdWV0dGUgYW5hbHlzaXMKYGBge3J9CnNldC5zZWVkKDMyMikKay5tYXggPC0gMTAKZGF0YSA8LSBmZWF0dXJlX3ZlY3Rvcl90cmFpbmluZwpucm93KGRhdGEpCnNpbCA8LSByZXAoMCwgay5tYXgpCiMgQ29tcHV0ZSB0aGUgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoIGZvciAKIyBrID0gMiB0byBrID0gMTUKCmZvcihpIGluIDI6ay5tYXgpewogIGttLnJlcyA8LSBrbWVhbnMoZGF0YSwgY2VudGVycyA9IGksIG5zdGFydCA9IDI1KQogIHNzIDwtIHNpbGhvdWV0dGUoa20ucmVzJGNsdXN0ZXIsIGRpc3QoZGF0YSkpCiAgc2lsW2ldIDwtIG1lYW4oc3NbLCAzXSkKfQojIFBsb3QgdGhlICBhdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGgKcGxvdCgxOmsubWF4LCBzaWwsIHR5cGUgPSAiYiIsIHBjaCA9IDE5LCAKICAgICBmcmFtZSA9IEZBTFNFLCB4bGFiID0gIk51bWJlciBvZiBjbHVzdGVycyBrIikKYWJsaW5lKHYgPSB3aGljaC5tYXgoc2lsKSwgbHR5ID0gMikKCmBgYAojIyMgVXNlZnVsIGZ1bmN0aW9ucwpgYGB7cn0KY29sZF9zdGFydF9kYXRhIDwtIGZ1bmN0aW9uKHRyYWluaW5nLnNhbXBsZWQsdGVzdGluZyxzZXR0aW5ncyl7CiAgbGlicmFyeShkb1BhcmFsbGVsKQogIGNsIDwtIG1ha2VDbHVzdGVyKDIpCiAgcmVnaXN0ZXJEb1BhcmFsbGVsKGNsKQogIHNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZy5zYW1wbGVkKQogIHNwbGl0X3NpemVfdHJhaW5pbmcgPSBzaXplX3RyYWluaW5nIC8gMjAwCiAgdGVzdGluZ19yZXN1bHQgPSBkYXRhLmZyYW1lKG51bWVyaWMobnJvdyh0ZXN0aW5nKSkpCiAgCiAgY291bnRfcmFuZG9tIDwtIGZvcmVhY2goaT0xOnNwbGl0X3NpemVfdHJhaW5pbmcpICVkb3BhciUgewogICAgMjAwICogaQogIH0KICBtZXRyaWMgPC0gbnVtZXJpYyhzcGxpdF9zaXplX3RyYWluaW5nKQogIG1ldHJpY190IDwtIG51bWVyaWMoc3BsaXRfc2l6ZV90cmFpbmluZykKICAjbWV0cmljIDwtIGZvcmVhY2goaT0xOnNwbGl0X3NpemVfdHJhaW5pbmcpICVkbyUgewogIGZvcihpIGluIGMoMTpzcGxpdF9zaXplX3RyYWluaW5nKSl7CiAgICAjbGlicmFyeShjYXJldCkKICAgICNsaWJyYXJ5KGRwbHlyKQogICAgY291bnQgPC0gMjAwICogaQogICAgYXV4X3RyYWluaW5nX3NldCA8LSB0cmFpbmluZy5zYW1wbGVkW2MoMTpjb3VudCksIF0jdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIGNvdW50KSwgXQogICAgY2x1c3RlcnMgPC0ga21lYW5zKGF1eF90cmFpbmluZ19zZXRbLC1jKDExLDEyLDEzLDE0KV0sMyxuc3RhcnQgPSAyNSkKICAgIGF1eF90cmFpbmluZ19zZXRfY2x1c3RlciA8LSBjYmluZChhdXhfdHJhaW5pbmdfc2V0LCBjbHVzdGVyID0gY2x1c3RlcnMkY2x1c3RlcikKICAgIHJlc3VsdF92ZWN0b3IgPC0gbnVtZXJpYyhucm93KHRlc3RpbmcpKQogICAgcmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmcgPC0gbnVtZXJpYyhucm93KGF1eF90cmFpbmluZ19zZXQpKQogICAgCiAgICBmb3IgKGogaW4gYygxOjMpKXsKICAgICAgY2x1c3Rlcl9kYXRhIDwtIGRwbHlyOjpmaWx0ZXIoYXV4X3RyYWluaW5nX3NldF9jbHVzdGVyLCBjbHVzdGVyID09IGopCiAgICAgIG5ld19yZkZpdCA8LSB0cmFpbihzdWJjbGFzcyB+IHNwK3dwK3ducCtzbnArZHMrZG0rZGwrc3Mrc20rc2wsCiAgICAgICAgICAgICAgICAgZGF0YSA9IGNsdXN0ZXJfZGF0YSwKICAgICAgICAgICAgICAgICBtZXRyaWM9IlJPQyIsCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwKICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBzZXR0aW5ncykKICAgICAgI1Rlc3RpbmcgcHJlZGljdAogICAgICBwcmVkc3JmcHJvYnMgPC0gcHJlZGljdChuZXdfcmZGaXQsdGVzdGluZyx0eXBlPSdwcm9iJykKICAgICAgCiAgICAgIGZvciAoayBpbiBjKDE6bGVuZ3RoKHJlc3VsdF92ZWN0b3IpKSl7CiAgICAgICAgaWYocHJlZHNyZnByb2JzJGJvdG5ldFtrXSA+IDAuNSl7CiAgICAgICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gKyAxCiAgICAgICAgfQogICAgICAgIGVsc2V7CiAgICAgICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gLSAxCiAgICAgICAgfQogICAgICB9CiAgICAgIAogICAgICAjVHJhaW5uaW5nIHByZWRpY3QKICAgICAgcHJlZHNyZnByb2JzX3QgPC0gcHJlZGljdChuZXdfcmZGaXQsYXV4X3RyYWluaW5nX3NldCx0eXBlPSdwcm9iJykKICAgICAgZm9yIChrIGluIGMoMTpsZW5ndGgocmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmcpKSl7CiAgICAgICAgaWYocHJlZHNyZnByb2JzX3QkYm90bmV0W2tdID4gMC41KXsKICAgICAgICAgIHJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nW2tdIDwtIHJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nW2tdICsgMQogICAgICAgIH0KICAgICAgICBlbHNlewogICAgICAgICAgcmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmdba10gPC0gcmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmdba10gLSAxCiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBhID0gaWZlbHNlKHJlc3VsdF92ZWN0b3IgPiAwLCdib3RuZXQnLCdub3JtYWwnKQogICAgYiA8LSBpZmVsc2UocmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmcgPiAwLCdib3RuZXQnLCdub3JtYWwnKQogICAgdGVzdGluZ19yZXN1bHQgPC0gY2JpbmQodGVzdGluZ19yZXN1bHQsJ3Jlc3VsdCcgPSByZXN1bHRfdmVjdG9yKQogICAgY20gPC0gY29uZnVzaW9uTWF0cml4KGEsdGVzdGluZyRzdWJjbGFzcykKICAgIG1ldHJpY1tpXSA8LSBjbSRieUNsYXNzWydGMSddI2NtJG92ZXJhbGxbMV0KICAgIAogICAgY21fdCA8LSBjb25mdXNpb25NYXRyaXgoYixhdXhfdHJhaW5pbmdfc2V0JHN1YmNsYXNzKQogICAgbWV0cmljX3RbaV0gPC0gY21fdCRieUNsYXNzWydGMSddCiAgICAjbGlzdCgnbWV0cmljJyA9IG1ldHJpYywgJ21ldHJpY190JyA9IG1ldHJpY190KQogIH0KICBvdXRwdXQgPC0gZG8uY2FsbChyYmluZCwgTWFwKGRhdGEuZnJhbWUsIGRhdGFfY291bnQ9Y291bnRfcmFuZG9tLCBtZXRyaWM9bWV0cmljKSkKICBvdXRwdXRfdCA8LSBkby5jYWxsKHJiaW5kLCBNYXAoZGF0YS5mcmFtZSwgZGF0YV9jb3VudD1jb3VudF9yYW5kb20sIG1ldHJpYz1tZXRyaWNfdCkpCiAgbGlzdF9yZXN1bHQgPC0gbGlzdCgnb3V0cHV0JyA9IG91dHB1dCwgJ291dHB1dF90JyA9IG91dHB1dF90LCAndGVzdGluZ19yZXN1bHQnID0gdGVzdGluZ19yZXN1bHQpCn0KCmNvbGRfc3RhcnRfZGF0YV9vbmx5X3JmIDwtIGZ1bmN0aW9uKHRyYWluaW5nLnNhbXBsZWQsdGVzdGluZyxzZXR0aW5ncyl7CiAgc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nLnNhbXBsZWQpCiAgc3BsaXRfc2l6ZV90cmFpbmluZyA9IHNpemVfdHJhaW5pbmcgLyAyMDAKICB0ZXN0aW5nX3Jlc3VsdCA9IGRhdGEuZnJhbWUobnVtZXJpYyhucm93KHRlc3RpbmcpKSkKICAKICBjb3VudF9yYW5kb20gPC0gZm9yZWFjaChpPTE6c3BsaXRfc2l6ZV90cmFpbmluZykgJWRvcGFyJSB7CiAgICAyMDAgKiBpCiAgfQogIG1ldHJpYyA8LSBudW1lcmljKHNwbGl0X3NpemVfdHJhaW5pbmcpCiAgbWV0cmljX3QgPC0gbnVtZXJpYyhzcGxpdF9zaXplX3RyYWluaW5nKQogICNtZXRyaWMgPC0gZm9yZWFjaChpPTE6c3BsaXRfc2l6ZV90cmFpbmluZykgJWRvJSB7CiAgZm9yKGkgaW4gYygxOnNwbGl0X3NpemVfdHJhaW5pbmcpKXsKICAgICNsaWJyYXJ5KGNhcmV0KQogICAgI2xpYnJhcnkoZHBseXIpCiAgICBjb3VudCA8LSAyMDAgKiBpCiAgICBhdXhfdHJhaW5pbmdfc2V0IDwtIHRyYWluaW5nLnNhbXBsZWRbYygxOmNvdW50KSwgXSN0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgY291bnQpLCBdCiAgICBuZXdfcmZGaXQgPC0gdHJhaW4oc3ViY2xhc3MgfiBzcCt3cCt3bnArc25wK2RzK2RtK2RsK3NzK3NtK3NsLAogICAgICAgICAgICAgICAgIGRhdGEgPSBhdXhfdHJhaW5pbmdfc2V0LAogICAgICAgICAgICAgICAgIG1ldHJpYz0iUk9DIiwKICAgICAgICAgICAgICAgICBtZXRob2QgPSAicmYiLAogICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHNldHRpbmdzKQogICAgI1Rlc3RpbmcgcHJlZGljdAogICAgcHJlZHNyZnByb2JzIDwtIHByZWRpY3QobmV3X3JmRml0LHRlc3RpbmcsdHlwZT0ncHJvYicpCiAgICBwcmVkc3JmIDwtIGlmZWxzZShwcmVkc3JmcHJvYnMkYm90bmV0ID49MC41LCdib3RuZXQnLCdub3JtYWwnKQogICAgY20gPC0gY29uZnVzaW9uTWF0cml4KHByZWRzcmYsdGVzdGluZyRzdWJjbGFzcykKICAgIG1ldHJpY1tpXSA8LSBjbSRieUNsYXNzWydGMSddCiAgICAKICAgIAogICAgI1RyYWlubmluZyBwcmVkaWN0CiAgICBwcmVkc3JmcHJvYnNfdCA8LSBwcmVkaWN0KG5ld19yZkZpdCxhdXhfdHJhaW5pbmdfc2V0LHR5cGU9J3Byb2InKQogICAgcHJlZHNyZl90IDwtIGlmZWxzZShwcmVkc3JmcHJvYnNfdCRib3RuZXQgPj0gMC41LCdib3RuZXQnLCdub3JtYWwnKQogICAgY21fdCA8LSBjb25mdXNpb25NYXRyaXgocHJlZHNyZl90LGF1eF90cmFpbmluZ19zZXQkc3ViY2xhc3MpCiAgICBtZXRyaWNfdFtpXSA8LSBjbV90JGJ5Q2xhc3NbJ0YxJ10KICAgIAogIH0KICBvdXRwdXQgPC0gZG8uY2FsbChyYmluZCwgTWFwKGRhdGEuZnJhbWUsIGRhdGFfY291bnQ9Y291bnRfcmFuZG9tLCBtZXRyaWM9bWV0cmljKSkKICBvdXRwdXRfdCA8LSBkby5jYWxsKHJiaW5kLCBNYXAoZGF0YS5mcmFtZSwgZGF0YV9jb3VudD1jb3VudF9yYW5kb20sIG1ldHJpYz1tZXRyaWNfdCkpCiAgbGlzdF9yZXN1bHQgPC0gbGlzdCgnb3V0cHV0JyA9IG91dHB1dCwgJ291dHB1dF90JyA9IG91dHB1dF90LCAndGVzdGluZ19yZXN1bHQnID0gdGVzdGluZ19yZXN1bHQpCn0KCmdlbmVyYXRlX2RhdGFfbm9pc3kgPC0gZnVuY3Rpb24oZGF0YXNldCwgcG9yY2VudCl7CiAgbGlzdF9hdXggPC0gc2FtcGxlKG5yb3coZGF0YXNldCkgLHBvcmNlbnQpCiAgbm9pc3lfZGF0YV9zYW1wbGUgPC0gZGF0YXNldFtsaXN0X2F1eCxdCiAgbm9fbm9pc3lfZGF0YV9zYW1wbGUgPC0gZGF0YXNldFstbGlzdF9hdXgsXQogIAogIG5vaXN5X2RhdGFfc2FtcGxlX2IgPC0gbm9pc3lfZGF0YV9zYW1wbGUgJT4lIGZpbHRlcihjbGFzcyA9PSAnQm90bmV0JykKICBub2lzeV9kYXRhX3NhbXBsZV9uIDwtIG5vaXN5X2RhdGFfc2FtcGxlICU+JSBmaWx0ZXIoY2xhc3MgPT0gJ05vcm1hbCcpCiAgCiAgbm9pc3lfZGF0YV9zYW1wbGVfYiRjbGFzcyA8LSBhcy5jaGFyYWN0ZXIobm9pc3lfZGF0YV9zYW1wbGVfYiRjbGFzcykKICBub2lzeV9kYXRhX3NhbXBsZV9iJGNsYXNzW25vaXN5X2RhdGFfc2FtcGxlX2IkY2xhc3MgPT0gJ0JvdG5ldCddIDwtICdOb3JtYWwnCiAgbm9pc3lfZGF0YV9zYW1wbGVfYiRjbGFzcyA8LSBhcy5mYWN0b3Iobm9pc3lfZGF0YV9zYW1wbGVfYiRjbGFzcykKICAKICBub2lzeV9kYXRhX3NhbXBsZV9uJGNsYXNzIDwtIGFzLmNoYXJhY3Rlcihub2lzeV9kYXRhX3NhbXBsZV9uJGNsYXNzKQogIG5vaXN5X2RhdGFfc2FtcGxlX24kY2xhc3Nbbm9pc3lfZGF0YV9zYW1wbGVfbiRjbGFzcyA9PSAnTm9ybWFsJ10gPC0gJ0JvdG5ldCcKICBub2lzeV9kYXRhX3NhbXBsZV9uJGNsYXNzIDwtIGFzLmZhY3Rvcihub2lzeV9kYXRhX3NhbXBsZV9uJGNsYXNzKQogIAogIG5vaXN5X2RhdGEgPC0gcmJpbmQobm9pc3lfZGF0YV9zYW1wbGVfYiwgbm9pc3lfZGF0YV9zYW1wbGVfbikKICB0cmFpbmluZ19ub2lzeSA8LSByYmluZChub19ub2lzeV9kYXRhX3NhbXBsZSxub2lzeV9kYXRhKQogIHRyYWluaW5nX25vaXN5IDwtIHRyYWluaW5nX25vaXN5W3NhbXBsZShucm93KHRyYWluaW5nX25vaXN5KSxucm93KHRyYWluaW5nX25vaXN5KSksXQogIHJldHVybih0cmFpbmluZ19ub2lzeSkKfQoKZ2V0X0VMQV9tZWFzdXJlIDwtIGZ1bmN0aW9uKEEwLCBBeCl7CiAgUkxBIDwtIGFicyhBMCAtIEF4KSAvIEEwCiAgRkEwIDwtICgxIC0gQTApIC8gQTAKICBFTEEgPC0gUkxBICsgRkEwCiAgcmV0dXJuKEVMQSkKfQoKcmFuZG9tRm9yZXN0X3BlcmZvcm1hY2UgPC0gZnVuY3Rpb24odHJhaW5pbmdfZGF0YSwgdGVzdGluZ19kYXRhKXsKICByZkZpdCA8LSB0cmFpbihjbGFzcyB+IHNwK3dwK3ducCtzbnArZHMrZG0rZGwrc3Mrc20rc2wsCiAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluaW5nX2RhdGEsCiAgICAgICAgICAgICAgICAgbWV0cmljPSJST0MiLAogICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJyZiIsCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gc2V0dGluZ3MpCiAgcHJlZHNyZnByb2JzIDwtIHByZWRpY3QocmZGaXQsdGVzdGluZ19kYXRhLHR5cGU9J3Byb2InKQogIHByZWRzcmYgPC0gaWZlbHNlKHByZWRzcmZwcm9icyRCb3RuZXQgPj0wLjUsJ0JvdG5ldCcsJ05vcm1hbCcpCiAgY20gPC0gY29uZnVzaW9uTWF0cml4KHByZWRzcmYsdGVzdGluZ19kYXRhJGNsYXNzKQogIHJlc3VsdCA8LSBjbSRieUNsYXNzCiAgcmV0dXJuKHJlc3VsdCkKfQoKZ2V0X3JhbmRvbUZvcmVzdF9wZXJmb3JtYWNlX3ZlY3RvciA8LSBmdW5jdGlvbih0cmFpbmluZ19kYXRhLCB0ZXN0aW5nX2RhdGEpewogIHJmRml0IDwtIHRyYWluKGNsYXNzIH4gc3Ard3Ard25wK3NucCtkcytkbStkbCtzcytzbStzbCwKICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5pbmdfZGF0YSwKICAgICAgICAgICAgICAgICBtZXRyaWM9IlJPQyIsCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwKICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBzZXR0aW5ncykKICBwcmVkc3JmcHJvYnMgPC0gcHJlZGljdChyZkZpdCx0ZXN0aW5nX2RhdGEsdHlwZT0ncHJvYicpCiAgcHJlZHNyZiA8LSBpZmVsc2UocHJlZHNyZnByb2JzJEJvdG5ldCA+PTAuNSwnQm90bmV0JywnTm9ybWFsJykKICByZXR1cm4ocHJlZHNyZikKfQoKY29zaW5lX3NpbWlsYXJpdHkgPC0gZnVuY3Rpb24odmVjdG9yLCBtYXRyaXgpewogIHJlc3VsdCA8LSBjKCkKICBmb3IoaSBpbiBjKDE6bnJvdyhtYXRyaXgpKSl7CiAgICB2MSA8LSBhcy5udW1lcmljKHZlY3RvcikKICAgIHYyIDwtIGFzLm51bWVyaWMoYXMudmVjdG9yKGFzLm1hdHJpeChtYXRyaXhbaSxdKSkpCiAgICByZXN1bHRbaV0gPSB2MSAlKiUgdjIgLyBzcXJ0KHYxICUqJSB2MSAqIHYyICUqJSB2MikKICB9CiAgcmV0dXJuKHJlc3VsdCkKfQoKcHJlZGljdGlvbl9ieV9zaW1pbGFyaXR5IDwtIGZ1bmN0aW9uKHRyYWluX2VsZW1lbnQsIHByZWRpY3Rpb25fZWxlbWVudCxudW1iZXJfZWxlbWVudCl7CiAgbnVtZXJpY190cmFpbl9lbGVtZW50IDwtIHRyYWluX2VsZW1lbnRbLDE6MTBdICNHZXR0aW5nIGNoYXJhY3RlcmlzdGljIG51bWVyaWMgdmVjdG9yCiAgc2ltaWxhcml0eV9yZXN1bHQgPC0gY29zaW5lX3NpbWlsYXJpdHkocHJlZGljdGlvbl9lbGVtZW50WzE6MTBdLG51bWVyaWNfdHJhaW5fZWxlbWVudCkKICB0cmFpbl9lbGVtZW50JHNpbWlsYXJpdHlfcmVzdWx0IDwtIHNpbWlsYXJpdHlfcmVzdWx0CiAgdHJhaW5fZWxlbWVudF9vcmRlcl9ieV9zaW1pbGFyaXR5IDwtIHRyYWluX2VsZW1lbnRbb3JkZXIodHJhaW5fZWxlbWVudCRzaW1pbGFyaXR5X3Jlc3VsdCwgZGVjcmVhc2luZyA9IFQpLF0KICB0cmFpbl9lbGVtZW50X29yZGVyX2J5X3NpbWlsYXJpdHkgPC0gdHJhaW5fZWxlbWVudF9vcmRlcl9ieV9zaW1pbGFyaXR5WzE6bnVtYmVyX2VsZW1lbnQsXQogIGF1eCA8LSB0cmFpbl9lbGVtZW50X29yZGVyX2J5X3NpbWlsYXJpdHkgJT4lIGdyb3VwX2J5KGNsYXNzKSAlPiUgc3VtbWFyaXNlKG49bigpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQogIHJlc3VsdCA8LSBhdXhbMSwxXQogIHJldHVybihyZXN1bHQpCn0KCnRyYWluaW5nCnRlc3RpbmcKYGBgCgojIyMgRGF0YSB0cmFpbmluZyBwYXJ0aXRpb25zOiBjb2xkIHN0YXJ0IHN0dWR5CiMjIyBJdGVyYXRpb24gIzEKYGBge3J9CnNldC5zZWVkKDIwMSkKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQp0cmFpbmluZy5zYW1wbGVkXzEgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCgpyZXN1bHQgPC0gY29sZF9zdGFydF9kYXRhKHRyYWluaW5nLnNhbXBsZWRfMSwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCm91dHB1dF8xIDwtIHJlc3VsdCRvdXRwdXQKb3V0cHV0X3RfMSA8LSByZXN1bHQkb3V0cHV0X3QKb3V0cHV0XzEKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0XzEpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQpmaXJzdF90cmFpbmluZ19zYW1wbGUgPC0gdHJhaW5pbmcuc2FtcGxlZF8xWzE6MjAwLF0KZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoc3ViY2xhc3MpKQpjbGFzc19kaXN0cmlidXRpb24gPC0gZmlyc3RfdHJhaW5pbmdfc2FtcGxlICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpnZ3Bsb3QoZmlyc3RfdHJhaW5pbmdfc2FtcGxlKSArIGdlb21fYmFyKGFlcyhjbGFzcykpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKCnRlc3RpbmdfcmVzdWx0IDwtIHJlc3VsdCR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3RfMSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKb3V0cHV0X3RfYXV4XzEgPC0gb3V0cHV0X3RfMQpuYW1lcyhvdXRwdXRfdF9hdXhfMSkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpvdXRwdXRfcmVzdWx0XzEgPC0gY2JpbmQob3V0cHV0XzEsb3V0cHV0X3RfYXV4XzEpCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3Jlc3VsdF8xKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAojIyMgSXRlcmF0aW9uICMyCmBgYHtyfQpzZXQuc2VlZCgyMDIpCnNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZykKdHJhaW5pbmcuc2FtcGxlZF8yIDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQoKcmVzdWx0XzIgPC0gY29sZF9zdGFydF9kYXRhKHRyYWluaW5nLnNhbXBsZWRfMiwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCm91dHB1dF8yIDwtIHJlc3VsdF8yJG91dHB1dApvdXRwdXRfdF8yIDwtIHJlc3VsdF8yJG91dHB1dF90Cm91dHB1dF8yCgpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF8yKQogIGdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICAgIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgICAgY29sb3I9TlVMTCkKZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHRyYWluaW5nLnNhbXBsZWRfMlsxOjIwMCxdCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKY2xhc3NfZGlzdHJpYnV0aW9uIDwtIGZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgp0ZXN0aW5nX3Jlc3VsdF8yIDwtIHJlc3VsdCR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3RfMikKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKb3V0cHV0X3RfYXV4XzIgPC0gb3V0cHV0X3RfMgpuYW1lcyhvdXRwdXRfdF9hdXhfMikgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpvdXRwdXRfcmVzdWx0XzIgPC0gY2JpbmQob3V0cHV0XzIsb3V0cHV0X3RfYXV4XzIpCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3Jlc3VsdF8yKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMwpgYGB7cn0Kc2V0LnNlZWQoMjMzKQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnRyYWluaW5nLnNhbXBsZWRfMyA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KCnJlc3VsdF8zIDwtIGNvbGRfc3RhcnRfZGF0YSh0cmFpbmluZy5zYW1wbGVkXzMsIHRlc3RpbmcsIHNldHRpbmdzID0gY3RybF9mYXN0KQpvdXRwdXRfMyA8LSByZXN1bHRfMyRvdXRwdXQKb3V0cHV0X3RfMyA8LSByZXN1bHRfMyRvdXRwdXRfdApvdXRwdXRfMwoKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0XzMpCiAgZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdyZWQnKSArIAogICAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgICB5PSJGMSBTY29yZSIsIAogICAgICAgICBjb2xvcj1OVUxMKQpmaXJzdF90cmFpbmluZ19zYW1wbGUgPC0gdHJhaW5pbmcuc2FtcGxlZF8zWzE6MjAwLF0KZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoc3ViY2xhc3MpKQpjbGFzc19kaXN0cmlidXRpb24gPC0gZmlyc3RfdHJhaW5pbmdfc2FtcGxlICU+JSBncm91cF9ieShjbGFzcykgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQpnZ3Bsb3QoZmlyc3RfdHJhaW5pbmdfc2FtcGxlKSArIGdlb21fYmFyKGFlcyhjbGFzcykpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKCnRlc3RpbmdfcmVzdWx0XzMgPC0gcmVzdWx0JHRlc3RpbmdfcmVzdWx0CiN0ZXN0aW5nX3Jlc3VsdAoKZ2cgPC0gZ2dwbG90KGRhdGEgPSBvdXRwdXRfdF8zKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCgpvdXRwdXRfdF9hdXhfMyA8LSBvdXRwdXRfdF8zCm5hbWVzKG91dHB1dF90X2F1eF8zKSA8LSBjKCdkYXRhX2NvdW50X3QnLCdtZXRyaWNfdCcpCm91dHB1dF9yZXN1bHRfMyA8LSBjYmluZChvdXRwdXRfMyxvdXRwdXRfdF9hdXhfMykKZ2cgPC0gZ2dwbG90KGRhdGEgPSBvdXRwdXRfcmVzdWx0XzMpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50X3QsIHkgPSBtZXRyaWNfdCksY29sb3IgPSAnYmx1ZScpICsgCiAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICB5PSJGMSBTY29yZSIsIAogICAgICAgY29sb3I9TlVMTCkKYGBgCgojIyMgSXRlcmF0aW9uICM0CmBgYHtyfQpzZXQuc2VlZCgyMDQpCnNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZykKdHJhaW5pbmcuc2FtcGxlZF80IDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQoKcmVzdWx0XzQgPC0gY29sZF9zdGFydF9kYXRhKHRyYWluaW5nLnNhbXBsZWRfNCwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCm91dHB1dF80IDwtIHJlc3VsdF80JG91dHB1dApvdXRwdXRfdF80IDwtIHJlc3VsdF80JG91dHB1dF90Cm91dHB1dF80CgpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF80KQogIGdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICAgIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgICAgY29sb3I9TlVMTCkKZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHRyYWluaW5nLnNhbXBsZWRfNFsxOjIwMCxdCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKY2xhc3NfZGlzdHJpYnV0aW9uIDwtIGZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KGZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgp0ZXN0aW5nX3Jlc3VsdF80IDwtIHJlc3VsdCR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3RfNCkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKb3V0cHV0X3RfYXV4XzQgPC0gb3V0cHV0X3RfNApuYW1lcyhvdXRwdXRfdF9hdXhfNCkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpvdXRwdXRfcmVzdWx0XzQgPC0gY2JpbmQob3V0cHV0XzQsb3V0cHV0X3RfYXV4XzQpCmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0X3Jlc3VsdF80KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjNQpgYGB7cn0Kc2V0LnNlZWQoMjA1KQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnRyYWluaW5nLnNhbXBsZWRfNSA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KCnJlc3VsdF81IDwtIGNvbGRfc3RhcnRfZGF0YSh0cmFpbmluZy5zYW1wbGVkXzUsIHRlc3RpbmcsIHNldHRpbmdzID0gY3RybF9mYXN0KQpvdXRwdXRfNSA8LSByZXN1bHRfNSRvdXRwdXQKb3V0cHV0X3RfNSA8LSByZXN1bHRfNSRvdXRwdXRfdApvdXRwdXRfNQoKZ2cgPC0gZ2dwbG90KGRhdGEgPSBvdXRwdXRfNSkKICBnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgCiAgICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICAgIGNvbG9yPU5VTEwpCmZpcnN0X3RyYWluaW5nX3NhbXBsZSA8LSB0cmFpbmluZy5zYW1wbGVkXzVbMToyMDAsXQpnZ3Bsb3QoZmlyc3RfdHJhaW5pbmdfc2FtcGxlKSArIGdlb21fYmFyKGFlcyhzdWJjbGFzcykpCmNsYXNzX2Rpc3RyaWJ1dGlvbiA8LSBmaXJzdF90cmFpbmluZ19zYW1wbGUgJT4lIGdyb3VwX2J5KGNsYXNzKSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKGNsYXNzKSkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQoKdGVzdGluZ19yZXN1bHRfNSA8LSByZXN1bHQkdGVzdGluZ19yZXN1bHQKI3Rlc3RpbmdfcmVzdWx0CgpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF90XzUpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAnYmx1ZScpICsgCiAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICB5PSJGMSBTY29yZSIsIAogICAgICAgY29sb3I9TlVMTCkKCm91dHB1dF90X2F1eF81IDwtIG91dHB1dF90XzUKbmFtZXMob3V0cHV0X3RfYXV4XzUpIDwtIGMoJ2RhdGFfY291bnRfdCcsJ21ldHJpY190JykKb3V0cHV0X3Jlc3VsdF81IDwtIGNiaW5kKG91dHB1dF81LG91dHB1dF90X2F1eF81KQpnZyA8LSBnZ3Bsb3QoZGF0YSA9IG91dHB1dF9yZXN1bHRfNSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdyZWQnKSArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnRfdCwgeSA9IG1ldHJpY190KSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQpgYGAKCiMjIyBEYXRhIHRyYWluaW5nIHBhcnRpdGlvbnM6IGNvbGQgc3RhcnQgc3R1ZHkgKHNpbXBsZSBSYW5kb20gRm9yZXN0KQpgYGB7cn0Kc2V0LnNlZWQoMjExKQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnJmX3RyYWluaW5nLnNhbXBsZWRfMSA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KcmZfcmVzdWx0XzEgPC0gY29sZF9zdGFydF9kYXRhX29ubHlfcmYocmZfdHJhaW5pbmcuc2FtcGxlZF8xLCB0ZXN0aW5nLCBzZXR0aW5ncyA9IGN0cmxfZmFzdCkKCnNldC5zZWVkKDIyMikKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQpyZl90cmFpbmluZy5zYW1wbGVkXzIgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCnJmX3Jlc3VsdF8yIDwtIGNvbGRfc3RhcnRfZGF0YV9vbmx5X3JmKHJmX3RyYWluaW5nLnNhbXBsZWRfMiwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCgpzZXQuc2VlZCgyMjMpCnNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZykKcmZfdHJhaW5pbmcuc2FtcGxlZF8zIDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQpyZl9yZXN1bHRfMyA8LSBjb2xkX3N0YXJ0X2RhdGFfb25seV9yZihyZl90cmFpbmluZy5zYW1wbGVkXzMsIHRlc3RpbmcsIHNldHRpbmdzID0gY3RybF9mYXN0KQoKc2V0LnNlZWQoMjI0KQpzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCnJmX3RyYWluaW5nLnNhbXBsZWRfNCA8LSB0cmFpbmluZ1tzYW1wbGUoc2l6ZV90cmFpbmluZywgc2l6ZV90cmFpbmluZyksIF0KcmZfcmVzdWx0XzQgPC0gY29sZF9zdGFydF9kYXRhX29ubHlfcmYocmZfdHJhaW5pbmcuc2FtcGxlZF80LCB0ZXN0aW5nLCBzZXR0aW5ncyA9IGN0cmxfZmFzdCkKCnNldC5zZWVkKDIyNSkKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQpyZl90cmFpbmluZy5zYW1wbGVkXzUgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCnJmX3Jlc3VsdF81IDwtIGNvbGRfc3RhcnRfZGF0YV9vbmx5X3JmKHJmX3RyYWluaW5nLnNhbXBsZWRfNSwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCgpyZl9kYXRhLnJlc3VsdCA8LSBkYXRhLmZyYW1lKHJmX3Jlc3VsdF81JG91dHB1dCRkYXRhX2NvdW50KQpyZl9kYXRhLnJlc3VsdF90IDwtIGRhdGEuZnJhbWUocmZfcmVzdWx0XzUkb3V0cHV0JGRhdGFfY291bnQpCmZvcihpIGluIGMoMTozMCkpewogIGN1cnJlbnRfc2VlZCA8LSAyMjYgKyBpCiAgc2V0LnNlZWQoY3VycmVudF9zZWVkKQogICNzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCiAgcmZfdHJhaW5pbmcuc2FtcGxlZF9jdXJyZW50IDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQogIHJmX3Jlc3VsdF9jdXJyZW50IDwtIGNvbGRfc3RhcnRfZGF0YV9vbmx5X3JmKHJmX3RyYWluaW5nLnNhbXBsZWRfY3VycmVudCwgdGVzdGluZywgc2V0dGluZ3MgPSBjdHJsX2Zhc3QpCiAgCiAgcmZfZGF0YS5yZXN1bHQgPC0gY2JpbmQocmZfZGF0YS5yZXN1bHQscmZfcmVzdWx0X2N1cnJlbnQkb3V0cHV0JG1ldHJpYykKICByZl9kYXRhLnJlc3VsdF90IDwtIGNiaW5kKHJmX2RhdGEucmVzdWx0X3QscmZfcmVzdWx0X2N1cnJlbnQkb3V0cHV0X3QkbWV0cmljKQp9CiAKIHggPC0gYygnY291bnRfb2ZfZGF0YScpCiBmb3IoaSBpbiBjKDE6MzApKXsKICAgeFtpKzFdIDwtIHBhc3RlKCdpdGVyYXRpb25fJyx0b1N0cmluZyhpKSxzZXAgPSAiIikKIH0KIHgKIG5hbWVzKHJmX2RhdGEucmVzdWx0KSA8LSB4CiBuYW1lcyhyZl9kYXRhLnJlc3VsdF90KSA8LSB4CiByZl9kYXRhLnJlc3VsdAogcmZfZGF0YS5yZXN1bHRfdCAKIAogI3dyaXRlLnRhYmxlKHJmX2RhdGEucmVzdWx0LGZpbGU9InJhbmRvbV9mb3Jlc3RfMzBfaXRlcmF0aW9uc19mMV90ZXN0aW5nLnR4dCIsc2VwPSJ8Iiwgcm93Lm5hbWVzID0gRikKICN3cml0ZS50YWJsZShyZl9kYXRhLnJlc3VsdF90LGZpbGU9InJhbmRvbV9mb3Jlc3RfMzBfaXRlcmF0aW9uc19mMV90cmFpbmluZy50eHQiLHNlcD0ifCIsIHJvdy5uYW1lcyA9IEYpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMQpgYGB7cn0KcmZfb3V0cHV0XzEgPC0gcmZfcmVzdWx0XzEkb3V0cHV0CnJmX291dHB1dF90XzEgPC0gcmZfcmVzdWx0XzEkb3V0cHV0X3QKcmZfb3V0cHV0XzEKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzEpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfMVsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMSA8LSByZl9yZXN1bHRfMSR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfMSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzEgPC0gcmZfb3V0cHV0X3RfMQpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfMSkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzEgPC0gY2JpbmQocmZfb3V0cHV0XzEscmZfb3V0cHV0X3RfYXV4XzEpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF8xKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMgpgYGB7cn0KcmZfb3V0cHV0XzIgPC0gcmZfcmVzdWx0XzIkb3V0cHV0CnJmX291dHB1dF90XzIgPC0gcmZfcmVzdWx0XzIkb3V0cHV0X3QKcmZfb3V0cHV0XzIKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzIpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfMlsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfMikKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzIgPC0gcmZfb3V0cHV0X3RfMgpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfMikgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzIgPC0gY2JpbmQocmZfb3V0cHV0XzIscmZfb3V0cHV0X3RfYXV4XzIpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF8yKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjMwpgYGB7cn0KcmZfb3V0cHV0XzMgPC0gcmZfcmVzdWx0XzMkb3V0cHV0CnJmX291dHB1dF90XzMgPC0gcmZfcmVzdWx0XzMkb3V0cHV0X3QKcmZfb3V0cHV0XzMKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzMpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfM1sxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfMykKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzMgPC0gcmZfb3V0cHV0X3RfMwpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfMykgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzMgPC0gY2JpbmQocmZfb3V0cHV0XzMscmZfb3V0cHV0X3RfYXV4XzMpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF8zKQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjNApgYGB7cn0KcmZfb3V0cHV0XzQgPC0gcmZfcmVzdWx0XzQkb3V0cHV0CnJmX291dHB1dF90XzQgPC0gcmZfcmVzdWx0XzQkb3V0cHV0X3QKcmZfb3V0cHV0XzQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzQpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfNFsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfNCkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzQgPC0gcmZfb3V0cHV0X3RfNApuYW1lcyhyZl9vdXRwdXRfdF9hdXhfNCkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzQgPC0gY2JpbmQocmZfb3V0cHV0XzQscmZfb3V0cHV0X3RfYXV4XzQpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF80KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKIyMjIEl0ZXJhdGlvbiAjNQpgYGB7cn0KcmZfb3V0cHV0XzUgPC0gcmZfcmVzdWx0XzUkb3V0cHV0CnJmX291dHB1dF90XzUgPC0gcmZfcmVzdWx0XzUkb3V0cHV0X3QKcmZfb3V0cHV0XzUKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0XzUpCmdnICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudCwgeSA9IG1ldHJpYyksY29sb3IgPSAncmVkJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfZmlyc3RfdHJhaW5pbmdfc2FtcGxlIDwtIHJmX3RyYWluaW5nLnNhbXBsZWRfNVsxOjIwMCxdCmdncGxvdChyZl9maXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKcmZfY2xhc3NfZGlzdHJpYnV0aW9uIDwtIHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZ2dwbG90KHJmX2ZpcnN0X3RyYWluaW5nX3NhbXBsZSkgKyBnZW9tX2JhcihhZXMoY2xhc3MpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgojcmZfdGVzdGluZ19yZXN1bHRfMiA8LSByZl9yZXN1bHRfMiR0ZXN0aW5nX3Jlc3VsdAojdGVzdGluZ19yZXN1bHQKCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3RfNSkKZ2cgKyBnZW9tX2xpbmUoYWVzKHggPSBkYXRhX2NvdW50LCB5ID0gbWV0cmljKSxjb2xvciA9ICdibHVlJykgKyAKICBsYWJzKHRpdGxlPSJSYW5kb20gRm9yZXN0IHRocm91Z2ggZGF0YSB0cmFpbmluZyBzaXplIiwgCiAgICAgICAjc3VidGl0bGU9IkRyYXduIGZyb20gTG9uZyBEYXRhIGZvcm1hdCIsIAogICAgICAgY2FwdGlvbj0iU291cmNlOiBDVFUtMTMiLCAKICAgICAgIHk9IkYxIFNjb3JlIiwgCiAgICAgICBjb2xvcj1OVUxMKQoKcmZfb3V0cHV0X3RfYXV4XzUgPC0gcmZfb3V0cHV0X3RfNQpuYW1lcyhyZl9vdXRwdXRfdF9hdXhfNSkgPC0gYygnZGF0YV9jb3VudF90JywnbWV0cmljX3QnKQpyZl9vdXRwdXRfcmVzdWx0XzUgPC0gY2JpbmQocmZfb3V0cHV0XzUscmZfb3V0cHV0X3RfYXV4XzUpCmdnIDwtIGdncGxvdChkYXRhID0gcmZfb3V0cHV0X3Jlc3VsdF81KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0YV9jb3VudF90LCB5ID0gbWV0cmljX3QpLGNvbG9yID0gJ2JsdWUnKSArIAogIGxhYnModGl0bGU9IlJhbmRvbSBGb3Jlc3QgdGhyb3VnaCBkYXRhIHRyYWluaW5nIHNpemUiLCAKICAgICAgICNzdWJ0aXRsZT0iRHJhd24gZnJvbSBMb25nIERhdGEgZm9ybWF0IiwgCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IENUVS0xMyIsIAogICAgICAgeT0iRjEgU2NvcmUiLCAKICAgICAgIGNvbG9yPU5VTEwpCmBgYAoKCiMjIyBTdHVkaWVzIFNhbXBsZXMKYGBge3J9CmZpcnN0X3RyYWluaW5nX3NhbXBsZSA8LSB0cmFpbmluZy5zYW1wbGVkWzE6MjAwLF0KZmlyc3RfdHJhaW5pbmdfc2FtcGxlCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKHN1YmNsYXNzKSkKCmNsYXNzX2Rpc3RyaWJ1dGlvbiA8LSBmaXJzdF90cmFpbmluZ19zYW1wbGUgJT4lIGdyb3VwX2J5KGNsYXNzKSAlPiUgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmdncGxvdChmaXJzdF90cmFpbmluZ19zYW1wbGUpICsgZ2VvbV9iYXIoYWVzKGNsYXNzKSkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQoKYGBgCgoKIyMjIHBhcnQgMgpgYGB7cn0Kc2V0LnNlZWQoMjA2KQpsaWJyYXJ5KGRvUGFyYWxsZWwpCmNsIDwtIG1ha2VDbHVzdGVyKDIpCnJlZ2lzdGVyRG9QYXJhbGxlbChjbCkKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQpzcGxpdF9zaXplX3RyYWluaW5nID0gc2l6ZV90cmFpbmluZyAvIDIwMApjb3VudF9yYW5kb20gPC0gZm9yZWFjaChpPTE6c3BsaXRfc2l6ZV90cmFpbmluZykgJWRvcGFyJSB7CiAgMjAwICogaQp9CnRyYWluaW5nLnNhbXBsZWQgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCm1ldHJpYyA8LSBmb3JlYWNoKGk9MTpzcGxpdF9zaXplX3RyYWluaW5nKSAlZG8lIHsKICAjbGlicmFyeShjYXJldCkKICBjb3VudCA8LSAyMDAgKiBpCiAgYXV4X3RyYWluaW5nX3NldCA8LSB0cmFpbmluZy5zYW1wbGVkW2MoMTpjb3VudCksIF0jdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIGNvdW50KSwgXQogIGNsdXN0ZXJzIDwtIGttZWFucyhhdXhfdHJhaW5pbmdfc2V0WywtYygxMSwxMiwxMywxNCldLDMsbnN0YXJ0ID0gMjUpCiAgYXV4X3RyYWluaW5nX3NldF9jbHVzdGVyIDwtIGNiaW5kKGF1eF90cmFpbmluZ19zZXQsIGNsdXN0ZXIgPSBjbHVzdGVycyRjbHVzdGVyKQogIHJlc3VsdF92ZWN0b3IgPC0gbnVtZXJpYyhucm93KHRlc3RpbmcpKQogIGZvciAoaiBpbiBjKDE6MykpewogICAgY2x1c3Rlcl9kYXRhIDwtIGZpbHRlcihhdXhfdHJhaW5pbmdfc2V0X2NsdXN0ZXIsIGNsdXN0ZXIgPT0gaikKICAgIG5ld19yZkZpdCA8LSB0cmFpbihjbGFzcyB+IHNwK3dwK3ducCtzbnArZHMrZG0rZGwrc3Mrc20rc2wsCiAgICAgICAgICAgICAgIGRhdGEgPSBjbHVzdGVyX2RhdGEsCiAgICAgICAgICAgICAgIG1ldHJpYz0iUk9DIiwKICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwKICAgICAgICAgICAgICAgdHJDb250cm9sID0gY3RybF9mYXN0KQogICAgcHJlZHNyZnByb2JzIDwtIHByZWRpY3QobmV3X3JmRml0LHRlc3RpbmcsdHlwZT0ncHJvYicpCiAgICBmb3IgKGsgaW4gYygxOmxlbmd0aChyZXN1bHRfdmVjdG9yKSkpewogICAgICBpZihwcmVkc3JmcHJvYnMkQm90bmV0W2tdID4gMC41KXsKICAgICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gKyAxCiAgICAgIH0KICAgICAgZWxzZXsKICAgICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gLSAxCiAgICAgIH0KICAgIH0KICAgIAogIH0KICBhID0gaWZlbHNlKHJlc3VsdF92ZWN0b3IgPiAwLCdCb3RuZXQnLCdOb3JtYWwnKQogIGNtIDwtIGNvbmZ1c2lvbk1hdHJpeChhLHRlc3RpbmckY2xhc3MpCiAgbWV0cmljIDwtIGNtJGJ5Q2xhc3NbJ0YxJ10jY20kb3ZlcmFsbFsxXQogIG1ldHJpYwogIAp9CgpvdXRwdXQgPC0gZG8uY2FsbChyYmluZCwgTWFwKGRhdGEuZnJhbWUsIGRhdGFfY291bnQ9Y291bnRfcmFuZG9tLCBtZXRyaWM9bWV0cmljKSkKb3V0cHV0CmdnIDwtIGdncGxvdChkYXRhID0gb3V0cHV0KQpnZyArIGdlb21fbGluZShhZXMoeCA9IGRhdGFfY291bnQsIHkgPSBtZXRyaWMpLGNvbG9yID0gJ3JlZCcpICsgCiAgbGFicyh0aXRsZT0iUmFuZG9tIEZvcmVzdCB0aHJvdWdoIGRhdGEgdHJhaW5pbmcgc2l6ZSIsIAogICAgICAgI3N1YnRpdGxlPSJEcmF3biBmcm9tIExvbmcgRGF0YSBmb3JtYXQiLCAKICAgICAgIGNhcHRpb249IlNvdXJjZTogQ1RVLTEzIiwgCiAgICAgICB5PSJBY2N1cmFjeSIsIAogICAgICAgY29sb3I9TlVMTCkKY2x1c3Rlcl9kYXRhCmBgYAoKCiMjIyBUZXN0IHdpdGggb25seSBvbmUKYGBge3J9CnNldC5zZWVkKDIyNikKc2l6ZV90cmFpbmluZyA8LSBucm93KHRyYWluaW5nKQp0cmFpbmluZy5zYW1wbGVkIDwtIHRyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCBzaXplX3RyYWluaW5nKSwgXQoKYXV4X3RyYWluaW5nX3NldCA8LSB0cmFpbmluZy5zYW1wbGVkW2MoMToyMDApLCBdI3RyYWluaW5nW3NhbXBsZShzaXplX3RyYWluaW5nLCAyMDApLCBdCmNsdXN0ZXJzIDwtIGttZWFucyhhdXhfdHJhaW5pbmdfc2V0WywtYygxMSwxMiwxMywxNCldLDMsbnN0YXJ0ID0gMjUpCmF1eF90cmFpbmluZ19zZXRfY2x1c3RlciA8LSBjYmluZChhdXhfdHJhaW5pbmdfc2V0LCBjbHVzdGVyID0gY2x1c3RlcnMkY2x1c3RlcikKcmVzdWx0X3ZlY3RvciA8LSBudW1lcmljKG5yb3codGVzdGluZykpCnJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nIDwtIG51bWVyaWMobnJvdyhhdXhfdHJhaW5pbmdfc2V0KSkKCmZvciAoaiBpbiBjKDE6MykpewogIGNsdXN0ZXJfZGF0YSA8LSBhdXhfdHJhaW5pbmdfc2V0X2NsdXN0ZXIgJT4lIGZpbHRlcihjbHVzdGVyID09IGopCiAgbmV3X3JmRml0IDwtIHRyYWluKHN1YmNsYXNzIH4gc3Ard3Ard25wK3NucCtkcytkbStkbCtzcytzbStzbCwKICAgICAgICAgICAgICAgZGF0YSA9IGNsdXN0ZXJfZGF0YSwKICAgICAgICAgICAgICAgbWV0cmljPSJST0MiLAogICAgICAgICAgICAgICBtZXRob2QgPSAicmYiLAogICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBjdHJsX2Zhc3QpCiAgcHJlZHNyZnByb2JzIDwtIHByZWRpY3QobmV3X3JmRml0LHRlc3RpbmcsdHlwZT0ncHJvYicpCiAgZm9yIChrIGluIGMoMTpsZW5ndGgocmVzdWx0X3ZlY3RvcikpKXsKICAgIGlmKHByZWRzcmZwcm9icyRib3RuZXRba10gPiAwLjUpewogICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gKyAxCiAgICB9CiAgICBlbHNlewogICAgICByZXN1bHRfdmVjdG9yW2tdIDwtIHJlc3VsdF92ZWN0b3Jba10gLSAxCiAgICB9CiAgfQogIAogICNUcmFpbm5pbmcgcHJlZGljdAogIHByZWRzcmZwcm9ic190IDwtIHByZWRpY3QobmV3X3JmRml0LGF1eF90cmFpbmluZ19zZXQsdHlwZT0ncHJvYicpCiAgZm9yIChrIGluIGMoMTpsZW5ndGgocmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmcpKSl7CiAgICBpZihwcmVkc3JmcHJvYnNfdCRib3RuZXRba10gPiAwLjUpewogICAgICByZXN1bHRfdmVjdG9yX3RyYWlubmluZ1trXSA8LSByZXN1bHRfdmVjdG9yX3RyYWlubmluZ1trXSArIDEKICAgIH0KICAgIGVsc2V7CiAgICAgIHJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nW2tdIDwtIHJlc3VsdF92ZWN0b3JfdHJhaW5uaW5nW2tdIC0gMQogICAgfQogIH0KfQoKYSA9IGlmZWxzZShyZXN1bHRfdmVjdG9yID4gMCwnYm90bmV0Jywnbm9ybWFsJykKYiA8LSBpZmVsc2UocmVzdWx0X3ZlY3Rvcl90cmFpbm5pbmcgPiAwLCdib3RuZXQnLCdub3JtYWwnKQpjbSA8LSBjb25mdXNpb25NYXRyaXgoYSx0ZXN0aW5nJHN1YmNsYXNzKQptZXRyaWMgPC0gY20kYnlDbGFzc1snRjEnXSNjbSRvdmVyYWxsWzFdCm1ldHJpYwpjbV90IDwtIGNvbmZ1c2lvbk1hdHJpeChiLGF1eF90cmFpbmluZ19zZXQkc3ViY2xhc3MpCm1ldHJpY190IDwtIGNtX3QkYnlDbGFzc1snRjEnXQptZXRyaWNfdApgYGAKCiMjIyBTYW1wbGUgZXhhbXBsZXMKYGBge3J9CnNldC5zZWVkKDU1NikKYSA9IGMoMSwyLDMsNCw1LDYsNyw4LDkpCnIgPC0gc2FtcGxlKDksMykKYVtyXQpyMiA8LSBzYW1wbGUoOSwzKQphW3IyXQpgYGAKCmBgYHtyfQojdGVzdGluZ19yZXN1bHQKdGVzdGluZ19yZXN1bHQuYmtwIDwtIHRlc3RpbmdfcmVzdWx0CnRlc3RpbmdfcmVzdWx0Cm5hbWVzX2F1eCA8LSBmb3JlYWNoKGk9MToobnJvdyh0cmFpbmluZykvMjAwKSkgJWRvJSB7CiAgICBpdGVyYXRpb24gPC0gMjAwICogaQogICAgcGFzdGUoJ3NpemVfJyx0b1N0cmluZyhpdGVyYXRpb24pLHNlcCA9ICIiKQp9CnRlc3RpbmdfcmVzdWx0X25hbWVzIDwtIHVubGlzdChuYW1lc19hdXgsIHVzZS5uYW1lcz1GQUxTRSkKdGVzdGluZ19yZXN1bHQgPC0gdGVzdGluZ19yZXN1bHRbLGMoLTEpXQpuYW1lcyh0ZXN0aW5nX3Jlc3VsdCkgPC0gdGVzdGluZ19yZXN1bHRfbmFtZXMKdGVzdGluZ19yZXN1bHQKCnRlc3RpbmdfYXV4IDwtIGNiaW5kKHRlc3RpbmcsdGVzdGluZ19yZXN1bHQpCnRlc3RpbmdfYXV4LmJrcDIgPC0gdGVzdGluZ19hdXgKI3dyaXRlLnRhYmxlKHRlc3RpbmdfYXV4LGZpbGU9InRlc3RpbmdfY2x1c3Rlcl9yZXN1bHQudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQp0ZXN0aW5nX2F1eApzdW1zIDwtIHJvd1N1bXModGVzdGluZ19hdXhbLC1jKDE6MTQpXSkKc3Vtcwp0ZXN0aW5nX2F1eFssLWMoMToxNCldCnRlc3RpbmdfYXV4IDwtIGNiaW5kKHRlc3RpbmdfYXV4LHN1bXMpCnRlc3RpbmdfYXV4CnRlc3RpbmdfYXV4X3Jlc3VsdCA8LSB0ZXN0aW5nX2F1eCAlPiUgZ3JvdXBfYnkoY2xhc3MpICU+JSBzdW1tYXJpc2UobiA9IG4oKSwgc3VtcyA9IHN1bShzdW1zKSkgJT4lIGFycmFuZ2UoZGVzYyhzdW1zKSkKdGVzdGluZ19hdXhfcmVzdWx0CgpncmFwaF90ZXN0aW5nX3Jlc3VsdCA8LSBnZ3Bsb3QodGVzdGluZ19hdXhfcmVzdWx0Wy1jKDEsbnJvdyh0ZXN0aW5nX2F1eF9yZXN1bHQpKSxdKQpncmFwaF90ZXN0aW5nX3Jlc3VsdCArIGdlb21fcG9pbnQoYWVzKGNsYXNzLHN1bXMpKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCgpmZWF0dXJlX3ZlY3RvcnNfY2xlYW5lZAoKbGlicmFyeShncmlkRXh0cmEpCnBkZigiZGF0YV9vdXRwdXQucGRmIiwgaGVpZ2h0PTExLCB3aWR0aD04LjUpCmdyaWQudGFibGUoZmVhdHVyZV92ZWN0b3JzX2NsZWFuZWRbMToyMCxdKQpkZXYub2ZmKCkKCnRlc3RpbmdfcmVzdWx0LmJrcAp0ZXN0aW5nX2F1eC5ia3AyCnRlc3RpbmdfYXV4X3Jlc3VsdAoKcnVzdHlfZGF0YV9yZXN1bHQgPC0gdGVzdGluZ19hdXguYmtwMgpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydCA8LSBydXN0eV9kYXRhX3Jlc3VsdFssLWMoMToxMSwxNCldCnJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0WywtYygxLDIpXQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydCRwb3MgPC0gcm93U3VtcyhydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydFssLWMoMSwyKV0gPiAwKQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydCRuZWcgPC0gcm93U3VtcyhydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydFssLWMoMSwyKV0gPCAwKQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydF9jbGVhbmVkIDwtIHJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0WyxjKDEsMiw0Niw0NyldCnJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWQKcnVzdHlfZGF0YV9yZXN1bHRfc2hvcnRfY2xlYW5lZF9yZXN1bHQgPC0gcnVzdHlfZGF0YV9yZXN1bHRfc2hvcnRfY2xlYW5lZCAlPiUgbXV0YXRlKGdvb2QgPSBpZmVsc2Uoc3ViY2xhc3MgPT0gJ25vcm1hbCcsbmVnLHBvcykpCnJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWRfcmVzdWx0IDwtIHJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWRfcmVzdWx0ICU+JSBtdXRhdGUoYmFkID0gaWZlbHNlKHN1YmNsYXNzID09ICdub3JtYWwnLHBvcyxuZWcpKQpydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydF9jbGVhbmVkX3Jlc3VsdCAlPiUgZ3JvdXBfYnkocG9ydCkgJT4lIHN1bW1hcmlzZShuPW4oKSxnb29kID0gc3VtKGdvb2QpLGJhZCA9IHN1bShiYWQpKSAlPiUgYXJyYW5nZShkZXNjKG4pKQoKZGF0YV9ib3RuZXRfcG9ydCA8LSBydXN0eV9kYXRhX3Jlc3VsdF9zaG9ydF9jbGVhbmVkX3Jlc3VsdCAlPiUgZmlsdGVyKHN1YmNsYXNzID09ICdib3RuZXQnKQpkYXRhX25vcm1hbF9wb3J0IDwtIHJ1c3R5X2RhdGFfcmVzdWx0X3Nob3J0X2NsZWFuZWRfcmVzdWx0ICU+JSBmaWx0ZXIoc3ViY2xhc3MgPT0gJ25vcm1hbCcpCmRhdGFfYm90bmV0X3BvcnRfcmVzdWx0IDwtICBkYXRhX2JvdG5ldF9wb3J0ICU+JSBncm91cF9ieShwb3J0KSAlPiUgc3VtbWFyaXNlKG49bigpLGdvb2QgPSBzdW0oZ29vZCksYmFkID0gc3VtKGJhZCkpICU+JSBhcnJhbmdlKGRlc2MobikpCmRhdGFfbm9ybWFsX3BvcnRfcmVzdWx0IDwtIGRhdGFfbm9ybWFsX3BvcnQgJT4lIGdyb3VwX2J5KHBvcnQpICU+JSBzdW1tYXJpc2Uobj1uKCksZ29vZCA9IHN1bShnb29kKSxiYWQgPSBzdW0oYmFkKSkgJT4lIGFycmFuZ2UoZGVzYyhuKSkKZGF0YV9ib3RuZXRfcG9ydF9yZXN1bHQKZGF0YV9ub3JtYWxfcG9ydF9yZXN1bHQKCmdncGxvdChkYXRhID0gZGF0YV9ib3RuZXRfcG9ydF9yZXN1bHQpICsgCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gcG9ydCwgZmlsbCA9IGNsYXJpdHkpKQoKI3dyaXRlLnRhYmxlKGRhdGFfYm90bmV0X3BvcnRfcmVzdWx0LGZpbGU9ImRhdGFfYm90bmV0X3BvcnQudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQpsaWJyYXJ5KHJlc2hhcGUyKQpkYXRhIDwtIGRhdGFfYm90bmV0X3BvcnRfcmVzdWx0CmRhdGEkcG9ydCA8LSBhcy5mYWN0b3IoZGF0YSRwb3J0KQoKbWVsdChkYXRhWyxjKDEsMyw0KV0pCgpnZ3Bsb3QobWVsdChkYXRhWyxjKDEsMyw0KV0pKSsKICBnZW9tX2NvbChhZXMoeD1wb3J0LHk9dmFsdWUsZmlsbD12YXJpYWJsZSkpKwogICN0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKI01ha2luZyBOb2lzeSBkYXRhICh0cmFpbmluZ19ub2lzeTogZGF0YXNldCB0byB0cmFpbiB3aXRoIDIwJSBvZiBub2lzeSkKYGBge3J9CnNldC5zZWVkKDEwMSkgCnRyYWluaW5nLmJrcCA8LSB0cmFpbmluZwpub2lzeV9kYXRhIDwtIHRyYWluaW5nCgpwb3JjZW50IDwtIG5yb3codHJhaW5pbmcpIC8gNQp0cmFpbmluZ19ub2lzeSA8LSBnZW5lcmF0ZV9kYXRhX25vaXN5KG5vaXN5X2RhdGEscG9yY2VudCkKbnJvdyh0cmFpbmluZykKbnJvdyh0cmFpbmluZ19ub2lzeSkKYGBgCgpgYGB7cn0KcmZGaXQgPC0gdHJhaW4oY2xhc3MgfiBzcCt3cCt3bnArc25wK2RzK2RtK2RsK3NzK3NtK3NsLAogICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbmluZywKICAgICAgICAgICAgICAgICBtZXRyaWM9IlJPQyIsCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwKICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBzZXR0aW5ncykKcHJlZHNyZnByb2JzIDwtIHByZWRpY3QocmZGaXQsdGVzdGluZyx0eXBlPSdwcm9iJykKcHJlZHNyZiA8LSBpZmVsc2UocHJlZHNyZnByb2JzJEJvdG5ldCA+PTAuNSwnQm90bmV0JywnTm9ybWFsJykKY20gPC0gY29uZnVzaW9uTWF0cml4KHByZWRzcmYsdGVzdGluZyRjbGFzcykKcmVzdWx0IDwtIGNtJGJ5Q2xhc3NbMTFdCmNtJG92ZXJhbGxbMV0KYGBgCgojUm9idXN0bmVzcyBBbmFsaXN5cyhvbmUgc2ltcGxlIGl0ZXJhdGlvbikKYGBge3J9CnNldC5zZWVkKDMyMSkKcGFydGl0aW9ucyA8LSBzZXEoMiw5MCwyKQpyZl9tZWFzdXJlc19yZXN1bHQgPC0gYygpCmVsYV9tZWFzdXJlc19yZXN1bHQgPC0gYygpCnRvdGFsIDwtIG5yb3codHJhaW5pbmcpCmJhbGFuY2VkX2FjY3VyYWN5IDwtIHJhbmRvbUZvcmVzdF9wZXJmb3JtYWNlKHRyYWluaW5nLHRlc3RpbmcpCgpmb3IoaSBpbiBwYXJ0aXRpb25zKXsKICBwb3JjZW50IDwtIChpKnRvdGFsKSAvIDEwMAogIHRyYWluaW5nX25vaXN5IDwtIGdlbmVyYXRlX2RhdGFfbm9pc3kobm9pc3lfZGF0YSxwb3JjZW50KQogIGJhbGFuY2VkX2FjY3VyYWN5X2F1eCA8LSByYW5kb21Gb3Jlc3RfcGVyZm9ybWFjZSh0cmFpbmluZ19ub2lzeSx0ZXN0aW5nKQogIHJmX21lYXN1cmVzX3Jlc3VsdFtpXSA8LSBiYWxhbmNlZF9hY2N1cmFjeV9hdXgKfQoKZm9yKGkgaW4gcGFydGl0aW9ucyl7CiAgYmFsYW5jZWRfYWNjdXJhY3lfbm9pc3kgPC0gcmZfbWVhc3VyZXNfcmVzdWx0W2ldCiAgZWxhX21lYXN1cmVzX3Jlc3VsdFtpXSA8LSBnZXRfRUxBX21lYXN1cmUoQTAgPSBiYWxhbmNlZF9hY2N1cmFjeVsnQmFsYW5jZWQgQWNjdXJhY3knXSwgQXggPSBiYWxhbmNlZF9hY2N1cmFjeV9ub2lzeSkKfQoKcGxvdChlbGFfbWVhc3VyZXNfcmVzdWx0KQogcGxvdChyZl9tZWFzdXJlc19yZXN1bHQpCmBgYAoKI1JvYnVzdG5lc3MgQW5hbGlzeXMgYnkgcG9ydChPbmUgc2ltcGxlIEl0ZXJhdGlvbikKYGBge3J9CnNldC5zZWVkKDMyMSkKcGFydGl0aW9ucyA8LSBzZXEoMiw5MCwyKQpyZl9tZWFzdXJlc19yZXN1bHQgPC0gYygpCmVsYV9tZWFzdXJlc19yZXN1bHQgPC0gYygpCnRvdGFsIDwtIG5yb3codHJhaW5pbmcpCiNiYWxhbmNlZF9hY2N1cmFjeSA8LSByYW5kb21Gb3Jlc3RfcGVyZm9ybWFjZSh0cmFpbmluZyx0ZXN0aW5nKQpyZXN1bHQgPC0gdGVzdGluZwpmb3IoaSBpbiBwYXJ0aXRpb25zKXsKICBwb3JjZW50IDwtIChpKnRvdGFsKSAvIDEwMAogIHRyYWluaW5nX25vaXN5IDwtIGdlbmVyYXRlX2RhdGFfbm9pc3kobm9pc3lfZGF0YSxwb3JjZW50KQogIHZlY3Rvcl9wcmVkX3Jlc3VsdCA8LSBnZXRfcmFuZG9tRm9yZXN0X3BlcmZvcm1hY2VfdmVjdG9yKHRyYWluaW5nX25vaXN5LHRlc3RpbmcpCiAgaWYoc3VtKGlzLm5hKHZlY3Rvcl9wcmVkX3Jlc3VsdCkpID09IDApewogICAgcmVzdWx0IDwtIGNiaW5kKHJlc3VsdCwgdmVjdG9yX3ByZWRfcmVzdWx0KQogIH0KfQoKcmVzdWx0Cm5hbWVzKHJlc3VsdCkgPSBjKG5hbWVzKHRlc3RpbmcpLHBhc3RlKCdwbicscGFydGl0aW9ucyxzZXAgPSAnXycpKQpyZXN1bHQKd3JpdGUudGFibGUocmVzdWx0LGZpbGUgPSAibm9pc3lfYnlfcG9ydF9yZXN1bHQudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQpgYGAKCiNSb2J1c3RuZXNzIEFuYWxpc3lzOiBwbG90aW5nIGFjY3VyYWN5CmBgYHtyfQppbmRleCA8LSBzZXEoMiw5MCwyKQptZWFzdXJlX3Jlc3VsdCA8LSByZl9tZWFzdXJlc19yZXN1bHRbaW5kZXhdCnJsYV9tZWFzdXJlX2RhdGEgPC0gZGF0YS5mcmFtZShpbmRleCxtZWFzdXJlX3Jlc3VsdCkKbmFtZXMocmxhX21lYXN1cmVfZGF0YSkgPC0gYygnbm9pc2VfcG9yY2VudCcsJ2JhbGFuY2VkX2FjY3VyYWN5JykKCmc8LWdncGxvdChybGFfbWVhc3VyZV9kYXRhKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gbm9pc2VfcG9yY2VudCwgeSA9IGJhbGFuY2VkX2FjY3VyYWN5KSkgKyBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKHggPSBub2lzZV9wb3JjZW50LCB5ID0gYmFsYW5jZWRfYWNjdXJhY3kpKQpnZ3Bsb3RseShnKQpgYGAKCiNSb2J1c3RuZXNzIEFuYWxpc3lzOiBwbG90aW5nIEVMQSBtZWFzdXJlCmBgYHtyfQppbmRleCA8LSBzZXEoMiw5MCwyKQptZWFzdXJlX3Jlc3VsdCA8LSBlbGFfbWVhc3VyZXNfcmVzdWx0W2luZGV4XQplbGFfbWVhc3VyZV9kYXRhIDwtIGRhdGEuZnJhbWUoaW5kZXgsbWVhc3VyZV9yZXN1bHQpCm5hbWVzKGVsYV9tZWFzdXJlX2RhdGEpIDwtIGMoJ25vaXNlX3BvcmNlbnQnLCdlbGFfbWVhc3VyZScpCgpnZ3Bsb3QoZWxhX21lYXN1cmVfZGF0YSkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IG5vaXNlX3BvcmNlbnQsIHkgPSBlbGFfbWVhc3VyZSkpICsgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gbm9pc2VfcG9yY2VudCwgeSA9IGVsYV9tZWFzdXJlKSkKYGBgCgojUm9idXN0bmVzcyBBbmFsaXN5cygzMCBpdGVyYXRpb25zKQpgYGB7cn0Kc2V0LnNlZWQoMzMxKQpwYXJ0aXRpb25zIDwtIHNlcSgyLDkwLDIpCgp0b3RhbCA8LSBucm93KHRyYWluaW5nKQpyZXN1bHRfcmZfYWNjdXJhY3kgPC0gZGF0YS5mcmFtZSgnY291bnRfb2ZfZGF0YScgPSBwYXJ0aXRpb25zKQpyZXN1bHRfZWxhX21lYXN1cmUgPC0gZGF0YS5mcmFtZSgnY291bnRfb2ZfZGF0YScgPSBwYXJ0aXRpb25zKQp3cml0ZS50YWJsZShyZXN1bHRfcmZfYWNjdXJhY3ksZmlsZT0idGVzdF9yZXN1bHRfcmZfYWNjdXJhY3kudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQp3cml0ZS50YWJsZShyZXN1bHRfZWxhX21lYXN1cmUsZmlsZT0idGVzdF9yZXN1bHRfZWxhX21lYXN1cmUudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQpmb3IgKGogaW4gYygxOjMwKSl7CiAgcmZfbWVhc3VyZXNfcmVzdWx0IDwtIGMoKQogIGVsYV9tZWFzdXJlc19yZXN1bHQgPC0gYygpCiAgI0NhbGN1bGFuZG8gUkYgcGVyZm9ybWFuY2UgY29uIHZhcmlhY2lvbmVzIGVuIGVsIHBvcmNpZW50byBkZSBydWlkbyBlbiB0cmFpbmluZwogIGZvcihpIGluIHBhcnRpdGlvbnMpewogICAgcG9yY2VudCA8LSAoaSp0b3RhbCkgLyAxMDAKICAgIHRyYWluaW5nX25vaXN5IDwtIGdlbmVyYXRlX2RhdGFfbm9pc3kobm9pc3lfZGF0YSxwb3JjZW50KQogICAgYmFsYW5jZWRfYWNjdXJhY3lfYXV4IDwtIHJhbmRvbUZvcmVzdF9wZXJmb3JtYWNlKHRyYWluaW5nX25vaXN5LHRlc3RpbmcpCiAgICByZl9tZWFzdXJlc19yZXN1bHRbaV0gPC0gYmFsYW5jZWRfYWNjdXJhY3lfYXV4CiAgfQogICNDYWxjdWxhbmRvIEVMQSBtZWFzdXJlCiAgZm9yKGkgaW4gcGFydGl0aW9ucyl7CiAgICBiYWxhbmNlZF9hY2N1cmFjeV9ub2lzeSA8LSByZl9tZWFzdXJlc19yZXN1bHRbaV0KICAgIGVsYV9tZWFzdXJlc19yZXN1bHRbaV0gPC0gZ2V0X0VMQV9tZWFzdXJlKEEwID0gYmFsYW5jZWRfYWNjdXJhY3lbJ0JhbGFuY2VkIEFjY3VyYWN5J10sIEF4ID0gYmFsYW5jZWRfYWNjdXJhY3lfbm9pc3kpCiAgfQogIAogICNRdWVkYW5kb21lIGNvbiBsYXMgcG9zaWNpb25lcyBwYXJlcyBxdWUgc29uIGxhcyBxdWUgdGllbmVuIGxvcyB2YWxvcmVzCiAgZWxhX21lYXN1cmVzX3Jlc3VsdCA8LSBlbGFfbWVhc3VyZXNfcmVzdWx0W3BhcnRpdGlvbnNdCiAgcmZfbWVhc3VyZXNfcmVzdWx0IDwtIHJmX21lYXN1cmVzX3Jlc3VsdFtwYXJ0aXRpb25zXQogIAogIGNvbHVtX25hbWUgPC0gcGFzdGUoJ2l0ZXJhdGlvbl8nLHRvU3RyaW5nKGopLHNlcCA9ICIiKQogIHJlc3VsdF9yZl9hY2N1cmFjeSA8LSBjYmluZChyZXN1bHRfcmZfYWNjdXJhY3ksIGNvbHVtX25hbWUgPSByZl9tZWFzdXJlc19yZXN1bHQpCiAgcmVzdWx0X2VsYV9tZWFzdXJlIDwtIGNiaW5kKHJlc3VsdF9lbGFfbWVhc3VyZSwgY29sdW1fbmFtZSA9IGVsYV9tZWFzdXJlc19yZXN1bHQpCiAgCiAgd3JpdGUudGFibGUocmVzdWx0X3JmX2FjY3VyYWN5LGZpbGU9InRlc3RfcmVzdWx0X3JmX2FjY3VyYWN5LnR4dCIsc2VwPSJ8Iiwgcm93Lm5hbWVzID0gRikKICB3cml0ZS50YWJsZShyZXN1bHRfZWxhX21lYXN1cmUsZmlsZT0idGVzdF9yZXN1bHRfZWxhX21lYXN1cmUudHh0IixzZXA9InwiLCByb3cubmFtZXMgPSBGKQp9CgpyZXN1bHRfZWxhX21lYXN1cmUKcmVzdWx0X3JmX2FjY3VyYWN5CgpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTh9CnggPC0gYygnbm9zaXN5X3BvcmNlbnQnKQpmb3IoaSBpbiBjKDE6MzApKXsKIHhbaSsxXSA8LSBwYXN0ZSgnaXRlcmF0aW9uXycsdG9TdHJpbmcoaSksc2VwID0gIiIpCn0KeApyZXN1bHRfZWxhX21lYXN1cmUuYmtwIDwtIHJlc3VsdF9lbGFfbWVhc3VyZQpyZXN1bHRfcmZfYWNjdXJhY3kuYmtwIDwtIHJlc3VsdF9yZl9hY2N1cmFjeQpuYW1lcyhyZXN1bHRfZWxhX21lYXN1cmUpIDwtIHgKbmFtZXMocmVzdWx0X3JmX2FjY3VyYWN5KSA8LSB4CgpyZXN1bHRfcmZfYWNjdXJhY3kKZ2dwbG90KHJlc3VsdF9yZl9hY2N1cmFjeSAlPiUgZ2F0aGVyKCJpdGVyYXRpb24iLCJ2YWx1ZSIsMjozMSkpKwogIGdlb21fYm94cGxvdChhZXMoeD1hcy5mYWN0b3Iobm9zaXN5X3BvcmNlbnQpLHk9dmFsdWUpKSsKICBzdGF0X3N1bW1hcnkoZnVuLnk9ICJtZWFuIiwKICAgICAgICAgICAgICAgICBhZXMoeD1hcy5mYWN0b3Iobm9zaXN5X3BvcmNlbnQpLHk9dmFsdWUsY29sb3I9dmFsdWUpKQogICNzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gInJlZCIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAiYmx1ZSIsIG1pZHBvaW50ID0gMC41KQpgYGAKCiNDb3NpbmUgU2ltaWxhcml0eQpgYGB7cn0KdHJhaW5pbmcKdGVzdGluZwpwcmVkaWN0aW9uX3ZlY3RvciA8LSB0ZXN0aW5nWzEsXQpwcmVkaWN0aW9uX3ZlY3RvciA8LSBhcy52ZWN0b3IoYXMubWF0cml4KHByZWRpY3Rpb25fdmVjdG9yKSkKcmVzdWx0IDwtIHByZWRpY3Rpb25fYnlfc2ltaWxhcml0eSh0cmFpbmluZyxwcmVkaWN0aW9uX3ZlY3RvciwxMDApCnJlc3VsdAoKcmVzdWx0IDwtIGMoKQpmb3IoaSBpbiAxOm5yb3codGVzdGluZykpewogIHByZWRpY3Rpb25fdmVjdG9yIDwtIHRlc3RpbmdbaSxdCiAgcHJlZGljdGlvbl92ZWN0b3IgPC0gYXMudmVjdG9yKGFzLm1hdHJpeChwcmVkaWN0aW9uX3ZlY3RvcikpCiAgcmVzdWx0W2ldIDwtIHByZWRpY3Rpb25fYnlfc2ltaWxhcml0eSh0cmFpbmluZyxwcmVkaWN0aW9uX3ZlY3RvciwxMDApCn0KdmVjdG9yX3Jlc3VsdCA8LSB1bmxpc3QocmVzdWx0KQpjbSA8LSBjb25mdXNpb25NYXRyaXgodmVjdG9yX3Jlc3VsdCx0ZXN0aW5nJGNsYXNzKQpjbQpgYGAKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIApgYGB7cn0KY3NfZGF0YS5yZXN1bHQgPC0gZGF0YS5mcmFtZShyZl9yZXN1bHRfNSRvdXRwdXQkZGF0YV9jb3VudCkKI2ZvcihpIGluIGMoMToxKSl7CiAgY3VycmVudF9zZWVkIDwtIDIyNiAjKyBpCiAgc2V0LnNlZWQoY3VycmVudF9zZWVkKQogIAogIHNpemVfdHJhaW5pbmcgPC0gbnJvdyh0cmFpbmluZykKICBjc190cmFpbmluZy5zYW1wbGVkX2N1cnJlbnQgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCiAgc3BsaXRfc2l6ZV90cmFpbmluZyA9IHNpemVfdHJhaW5pbmcgLyAyMDAKICBtZXRyaWMgPC0gbnVtZXJpYyhzcGxpdF9zaXplX3RyYWluaW5nKQogIGZvcihqIGluIDE6c3BsaXRfc2l6ZV90cmFpbmluZyl7CiAgICBjb3VudCA8LSAyMDAgKiBqCiAgICBhdXhfdHJhaW5pbmdfc2V0IDwtIGNzX3RyYWluaW5nLnNhbXBsZWRfY3VycmVudFtjKDE6Y291bnQpLCBdCiAgICByZXN1bHQgPC0gYygpCiAgICBmb3IoayBpbiAxOm5yb3codGVzdGluZykpewogICAgICBwcmVkaWN0aW9uX3ZlY3RvciA8LSB0ZXN0aW5nW2ssXQogICAgICBwcmVkaWN0aW9uX3ZlY3RvciA8LSBhcy52ZWN0b3IoYXMubWF0cml4KHByZWRpY3Rpb25fdmVjdG9yKSkKICAgICAgb3V0cHV0X3Jlc3VsdCA8LSBwcmVkaWN0aW9uX2J5X3NpbWlsYXJpdHkoYXV4X3RyYWluaW5nX3NldCxwcmVkaWN0aW9uX3ZlY3RvciwxMDEpCiAgICAgIHJlc3VsdFtrXSA8LSBvdXRwdXRfcmVzdWx0CiAgICB9CiAgICB2ZWN0b3JfcmVzdWx0IDwtIHVubGlzdChyZXN1bHQpCiAgICBjbSA8LSBjb25mdXNpb25NYXRyaXgodmVjdG9yX3Jlc3VsdCx0ZXN0aW5nJGNsYXNzKQogICAgbWV0cmljW2pdIDwtIGNtJGJ5Q2xhc3NbJ0YxJ10KICAgIAogIH0KICBjc19kYXRhLnJlc3VsdCA8LSBjYmluZChjc19kYXRhLnJlc3VsdCwgbWV0cmljKQojfQpjc19kYXRhLnJlc3VsdApgYGAKCmBgYHtyfQpmb3IoaSBpbiBjKDE6MzApKXsKIGN1cnJlbnRfc2VlZCA8LSAyMjYgKyBpCiBzZXQuc2VlZChjdXJyZW50X3NlZWQpCiBzaXplX3RyYWluaW5nIDwtIG5yb3codHJhaW5pbmcpCiByZl90cmFpbmluZy5zYW1wbGVkX2N1cnJlbnQgPC0gdHJhaW5pbmdbc2FtcGxlKHNpemVfdHJhaW5pbmcsIHNpemVfdHJhaW5pbmcpLCBdCiAKIHByaW50X2RhdGEgPSByZl90cmFpbmluZy5zYW1wbGVkX2N1cnJlbnRbLGMoMToxMCwxNCldCiBmaWxlX25hbWUgPSBwYXN0ZShwYXN0ZSgidHJhaW5pbl9zYW1wbGUiLCBpLCBzZXAgPSAnXycpLCAnY3N2Jywgc2VwID0gJy4nKQogd3JpdGUuY3N2KHByaW50X2RhdGEsZmlsZT1maWxlX25hbWUgLCByb3cubmFtZXMgPSBGKQp9CiAKICN3cml0ZS5jc3YodGVzdGluZ1ssYygxOjExKV0sIGZpbGU9J3Rlc3RpbmcuY3N2Jywgcm93Lm5hbWVzID0gRikKYGBgCmBgYA==